<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
<meta name="viewport" content="width=device-width">
<meta name="theme-color" content="#222"><meta name="generator" content="Hexo 5.4.2">

  <link rel="apple-touch-icon" sizes="180x180" href="/images/apple-touch-icon-next.png">
  <link rel="icon" type="image/png" sizes="32x32" href="/images/favicon-32x32-next.png">
  <link rel="icon" type="image/png" sizes="16x16" href="/images/favicon-16x16-next.png">
  <link rel="mask-icon" href="/images/logo.svg" color="#222">

<link rel="stylesheet" href="/css/main.css">



<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css" integrity="sha256-HtsXJanqjKTc8vVQjO4YMhiqFoXkfBsjBWcX91T1jr8=" crossorigin="anonymous">
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/3.1.1/animate.min.css" integrity="sha256-PR7ttpcvz8qrF57fur/yAx1qXMFJeJFiA6pSzWi0OIE=" crossorigin="anonymous">

<script class="next-config" data-name="main" type="application/json">{"hostname":"xiaoqingming18.github.io","root":"/","images":"/images","scheme":"Muse","darkmode":false,"version":"8.15.1","exturl":false,"sidebar":{"position":"left","display":"post","padding":18,"offset":12},"copycode":{"enable":false,"style":null},"bookmark":{"enable":false,"color":"#222","save":"auto"},"mediumzoom":false,"lazyload":false,"pangu":false,"comments":{"style":"tabs","active":null,"storage":true,"lazyload":false,"nav":null},"stickytabs":false,"motion":{"enable":true,"async":false,"transition":{"menu_item":"fadeInDown","post_block":"fadeIn","post_header":"fadeInDown","post_body":"fadeInDown","coll_header":"fadeInLeft","sidebar":"fadeInUp"}},"prism":false,"i18n":{"placeholder":"搜索...","empty":"没有找到任何搜索结果：${query}","hits_time":"找到 ${hits} 个搜索结果（用时 ${time} 毫秒）","hits":"找到 ${hits} 个搜索结果"}}</script><script src="/js/config.js"></script>

    <meta name="description" content="记录我的学习、生活和恋爱日常">
<meta property="og:type" content="website">
<meta property="og:title" content="鸣蜩十七">
<meta property="og:url" content="http://xiaoqingming18.github.io/page/4/index.html">
<meta property="og:site_name" content="鸣蜩十七">
<meta property="og:description" content="记录我的学习、生活和恋爱日常">
<meta property="og:locale" content="zh_CN">
<meta property="article:author" content="鸣蜩十七">
<meta name="twitter:card" content="summary">


<link rel="canonical" href="http://xiaoqingming18.github.io/page/4/">



<script class="next-config" data-name="page" type="application/json">{"sidebar":"","isHome":true,"isPost":false,"lang":"zh-CN","comments":"","permalink":"","path":"page/4/index.html","title":""}</script>

<script class="next-config" data-name="calendar" type="application/json">""</script>
<title>鸣蜩十七</title>
  








  <noscript>
    <link rel="stylesheet" href="/css/noscript.css">
  </noscript>

<style>.github-emoji { position: relative; display: inline-block; width: 1.2em; min-height: 1.2em; overflow: hidden; vertical-align: top; color: transparent; }  .github-emoji > span { position: relative; z-index: 10; }  .github-emoji img, .github-emoji .fancybox { margin: 0 !important; padding: 0 !important; border: none !important; outline: none !important; text-decoration: none !important; user-select: none !important; cursor: auto !important; }  .github-emoji img { height: 1.2em !important; width: 1.2em !important; position: absolute !important; left: 50% !important; top: 50% !important; transform: translate(-50%, -50%) !important; user-select: none !important; cursor: auto !important; } .github-emoji-fallback { color: inherit; } .github-emoji-fallback img { opacity: 0 !important; }</style>
</head>

<body itemscope itemtype="http://schema.org/WebPage" class="use-motion">
  <div class="headband"></div>

  <main class="main">
    <div class="column">
      <header class="header" itemscope itemtype="http://schema.org/WPHeader"><div class="site-brand-container">
  <div class="site-nav-toggle">
    <div class="toggle" aria-label="切换导航栏" role="button">
        <span class="toggle-line"></span>
        <span class="toggle-line"></span>
        <span class="toggle-line"></span>
    </div>
  </div>

  <div class="site-meta">

    <a href="/" class="brand" rel="start">
      <i class="logo-line"></i>
      <h1 class="site-title">鸣蜩十七</h1>
      <i class="logo-line"></i>
    </a>
      <p class="site-subtitle" itemprop="description">鸣蜩十七是和女朋友谈恋爱的日子</p>
  </div>

  <div class="site-nav-right">
    <div class="toggle popup-trigger" aria-label="搜索" role="button">
    </div>
  </div>
</div>



<nav class="site-nav">
  <ul class="main-menu menu"><li class="menu-item menu-item-home"><a href="/" rel="section"><i class="fa fa-home fa-fw"></i>首页</a></li><li class="menu-item menu-item-about"><a href="/about/" rel="section"><i class="fa fa-user fa-fw"></i>关于</a></li><li class="menu-item menu-item-tags"><a href="/tags/" rel="section"><i class="fa fa-tags fa-fw"></i>标签</a></li><li class="menu-item menu-item-categories"><a href="/categories/" rel="section"><i class="fa fa-th fa-fw"></i>分类</a></li><li class="menu-item menu-item-archives"><a href="/archives/" rel="section"><i class="fa fa-archive fa-fw"></i>归档</a></li><li class="menu-item menu-item-schedule"><a href="/schedule/" rel="section"><i class="fa fa-calendar fa-fw"></i>日程表</a></li><li class="menu-item menu-item-sitemap"><a href="/sitemap.xml" rel="section"><i class="fa fa-sitemap fa-fw"></i>站点地图</a></li><li class="menu-item menu-item-commonweal"><a href="/404/" rel="section"><i class="fa fa-heartbeat fa-fw"></i>公益 404</a></li>
  </ul>
</nav>




</header>
        
  
  <aside class="sidebar">

    <div class="sidebar-inner sidebar-overview-active">
      <ul class="sidebar-nav">
        <li class="sidebar-nav-toc">
          文章目录
        </li>
        <li class="sidebar-nav-overview">
          站点概览
        </li>
      </ul>

      <div class="sidebar-panel-container">
        <!--noindex-->
        <div class="post-toc-wrap sidebar-panel">
        </div>
        <!--/noindex-->

        <div class="site-overview-wrap sidebar-panel">
          <div class="site-author animated" itemprop="author" itemscope itemtype="http://schema.org/Person">
  <p class="site-author-name" itemprop="name">鸣蜩十七</p>
  <div class="site-description" itemprop="description">记录我的学习、生活和恋爱日常</div>
</div>
<div class="site-state-wrap animated">
  <nav class="site-state">
      <div class="site-state-item site-state-posts">
        <a href="/archives/">
          <span class="site-state-item-count">43</span>
          <span class="site-state-item-name">日志</span>
        </a>
      </div>
      <div class="site-state-item site-state-categories">
          <a href="/categories/">
        <span class="site-state-item-count">8</span>
        <span class="site-state-item-name">分类</span></a>
      </div>
      <div class="site-state-item site-state-tags">
          <a href="/tags/">
        <span class="site-state-item-count">37</span>
        <span class="site-state-item-name">标签</span></a>
      </div>
  </nav>
</div>

        </div>
      </div>
    </div>

    
  </aside>


    </div>

    <div class="main-inner index posts-expand">

    


<div class="post-block">
  
  

  <article itemscope itemtype="http://schema.org/Article" class="post-content" lang="">
    <link itemprop="mainEntityOfPage" href="http://xiaoqingming18.github.io/2023/04/24/%E5%AF%B9%E8%B1%A1%E3%80%81%E7%B1%BB%E4%B8%8E%E9%9D%A2%E5%90%91%E5%AF%B9%E8%B1%A1%E7%BC%96%E7%A8%8B/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="image" content="/images/avatar.gif">
      <meta itemprop="name" content="鸣蜩十七">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="鸣蜩十七">
      <meta itemprop="description" content="记录我的学习、生活和恋爱日常">
    </span>

    <span hidden itemprop="post" itemscope itemtype="http://schema.org/CreativeWork">
      <meta itemprop="name" content="undefined | 鸣蜩十七">
      <meta itemprop="description" content="">
    </span>
      <header class="post-header">
        <h2 class="post-title" itemprop="name headline">
          <a href="/2023/04/24/%E5%AF%B9%E8%B1%A1%E3%80%81%E7%B1%BB%E4%B8%8E%E9%9D%A2%E5%90%91%E5%AF%B9%E8%B1%A1%E7%BC%96%E7%A8%8B/" class="post-title-link" itemprop="url">对象、类与面向对象编程</a>
        </h2>

        <div class="post-meta-container">
          <div class="post-meta">
    <span class="post-meta-item">
      <span class="post-meta-item-icon">
        <i class="far fa-calendar"></i>
      </span>
      <span class="post-meta-item-text">发表于</span>

      <time title="创建时间：2023-04-24 16:52:52" itemprop="dateCreated datePublished" datetime="2023-04-24T16:52:52+08:00">2023-04-24</time>
    </span>
    <span class="post-meta-item">
      <span class="post-meta-item-icon">
        <i class="far fa-calendar-check"></i>
      </span>
      <span class="post-meta-item-text">更新于</span>
      <time title="修改时间：2023-04-25 01:02:51" itemprop="dateModified" datetime="2023-04-25T01:02:51+08:00">2023-04-25</time>
    </span>
    <span class="post-meta-item">
      <span class="post-meta-item-icon">
        <i class="far fa-folder"></i>
      </span>
      <span class="post-meta-item-text">分类于</span>
        <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
          <a href="/categories/JavaScript/" itemprop="url" rel="index"><span itemprop="name">JavaScript</span></a>
        </span>
    </span>

  
</div>

        </div>
      </header>

    
    
    
    <div class="post-body" itemprop="articleBody">
          <h1 id="对象基础内容"><a href="#对象基础内容" class="headerlink" title="对象基础内容"></a>对象基础内容</h1><h2 id="创建对象的两种方法"><a href="#创建对象的两种方法" class="headerlink" title="创建对象的两种方法"></a>创建对象的两种方法</h2><p>一种是先创建对象（<code>Object</code>）的一个实例，再为其添加属性和方法，如下所示：</p>
<figure class="highlight javascript"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> girlFriend = <span class="keyword">new</span> <span class="title class_">Object</span>();</span><br><span class="line">person.<span class="property">name</span> = <span class="string">"吴大孬"</span>;</span><br><span class="line">person.<span class="property">age</span> = <span class="number">18</span>;</span><br><span class="line">person.<span class="property">say</span> = <span class="keyword">function</span>(<span class="params"></span>) {</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">"我爱小阿飞"</span>);</span><br><span class="line">};</span><br></pre></td></tr></tbody></table></figure>
<p>另一种是更流行的对象字面量方式创建：</p>
<figure class="highlight javascript"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> girlFriend = {</span><br><span class="line">    name = <span class="string">"吴大孬"</span>;</span><br><span class="line">	age = <span class="number">18</span>;</span><br><span class="line">    <span class="title function_">say</span>(<span class="params"></span>) {</span><br><span class="line">        <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">"我爱小阿飞"</span>);</span><br><span class="line">    }</span><br><span class="line">};</span><br></pre></td></tr></tbody></table></figure>
<h2 id="属性的类型及其特性"><a href="#属性的类型及其特性" class="headerlink" title="属性的类型及其特性"></a>属性的类型及其特性</h2><p>JavaScript使用一些<strong>内部特性</strong>来描述属性的特征。</p>
<p>JavaScript对象中的属性分为两类：<strong>数据属性</strong>和<strong>访问器属性</strong>。</p>
<h3 id="数据属性"><a href="#数据属性" class="headerlink" title="数据属性"></a>数据属性</h3><p>数据属性有以下4个内部特性来描述它们的行为：</p>
<ol>
<li><code>Congifurable</code>：默认为<code>true</code>，表示属性是否可以用<code>delete</code>删除，是否可以修改该属性的内部特性，以及是否可以把该属性改为访问器属性。</li>
<li><code>Enumberable</code>：默认为<code>true</code>，表示属性是否可以通过<code>for-in</code>循环返回。</li>
<li><code>Writable</code>：默认为<code>true</code>，表示属性的值是否可以被修改。</li>
<li><code>Value</code>：默认为<code>undefined</code>，此特性存储该属性的值。</li>
</ol>
<p>当我们显式地将属性添加到对象之后，<code>Configurable</code>、<code>Enumberable</code>和<code>Writable</code>都会被设置为<code>true</code>，而<code>Value</code>会被设置为给定的值，若没有为属性赋值，则<code>Value</code>为<code>undefined</code>。</p>
<p>可以使用<code>Object.defineProperty()</code>方法修改属性的默认特性。此方法接受3个参数：要给属性添加或修改特性的对象、属性名、描述符对象。其中，描述符对象上的属性名为要修改的特姓名，属性值为要给特性设置的值，看下面的例子：</p>
<figure class="highlight javascript"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> girlFriend = {};</span><br><span class="line"><span class="title class_">Object</span>.<span class="title function_">defineProperty</span>(girlFriend,<span class="string">"name"</span>,{</span><br><span class="line">    <span class="attr">writable</span>: <span class="literal">false</span>,</span><br><span class="line">    <span class="title class_">Value</span>: <span class="string">"吴大孬"</span></span><br><span class="line">});</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(girlFriend.<span class="property">name</span>); <span class="comment">// 吴大孬</span></span><br><span class="line">girlFriend.<span class="property">name</span> = <span class="string">"吴小孬"</span>; <span class="comment">// 因为设置了writable为false，即只读，无法修改</span></span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(girlFriend.<span class="property">name</span>); <span class="comment">// 吴大孬</span></span><br></pre></td></tr></tbody></table></figure>
<p>要注意的是，<strong>一个属性被定义为只读之后，就不可以再改为可修改的了</strong>。</p>
<p>并且，调用该方法修改属性的内部特性时，<strong>没有被指定的特性会默认为<code>false</code></strong>。</p>
<p>多数情况下并不需要使用此方法，此处只是为了了解JavaScript的对象特性。</p>
<h4 id="访问器属性"><a href="#访问器属性" class="headerlink" title="访问器属性"></a>访问器属性</h4><p>访问器属性不包含数据值，它们包含一个获取函数<code>get()</code>和一个设置函数<code>set()</code>。在读取访问器属性时，会调用获取函数返回一个有效值，在写入访问器属性时，会调用设置函数传入新值。</p>
<p>访问器属性有4个特性描述它们的行为：</p>
<ol>
<li><code>Configurable</code>：默认为<code>true</code>，表示属性是否可以用<code>delete</code>删除，是否可以修改该属性的内部特性，以及是否可以把该属性改为数据属性。</li>
<li><code>Enumberable</code>：默认为<code>true</code>，表示属性是否可以通过<code>for-in</code>循环返回。</li>
<li><code>Get</code>：获取函数，在读取属性时调用，默认为<code>undefined</code>。</li>
<li><code>Set</code>：设置函数，在写入属性时调用，默认为<code>undefined</code>。</li>
</ol>
<p><strong>访问器属性无法直接定义，必须使用<code>Object.defineProperty()</code>来定义</strong>。看下面的例子：</p>
<figure class="highlight javascript"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> book = {</span><br><span class="line">    <span class="attr">year_</span>: <span class="number">2017</span>,</span><br><span class="line">    <span class="attr">edition</span>: <span class="number">1</span></span><br><span class="line">};</span><br><span class="line"></span><br><span class="line"><span class="title class_">Object</span>.<span class="title function_">defineProperty</span>(book,<span class="string">"year"</span>,{</span><br><span class="line">    <span class="title function_">get</span>(<span class="params"></span>) {</span><br><span class="line">        <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="property">year_</span>;</span><br><span class="line">    },</span><br><span class="line">    <span class="title function_">set</span>(<span class="params">newValue</span>) {</span><br><span class="line">        <span class="keyword">if</span>(newValue &gt; <span class="number">2017</span>) {</span><br><span class="line">            <span class="variable language_">this</span>.<span class="property">year_</span> = newValue;</span><br><span class="line">            <span class="variable language_">this</span>,edition += newValue - <span class="number">2017</span>;</span><br><span class="line">        }</span><br><span class="line">    }</span><br><span class="line">});</span><br><span class="line"></span><br><span class="line">book.<span class="property">year</span> = <span class="number">2018</span>;</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(book.<span class="property">editon</span>); <span class="comment">// 2</span></span><br></pre></td></tr></tbody></table></figure>

      
    </div>

    
    
    

    <footer class="post-footer">
        <div class="post-eof"></div>
      
    </footer>
  </article>
</div>




    


<div class="post-block">
  
  

  <article itemscope itemtype="http://schema.org/Article" class="post-content" lang="">
    <link itemprop="mainEntityOfPage" href="http://xiaoqingming18.github.io/2023/04/24/%E6%95%B0%E6%8D%AE%E5%BA%93%E5%8E%9F%E7%90%86%EF%BC%9A%E6%B1%82%E6%9C%80%E5%B0%8F%E4%BE%9D%E8%B5%96%E9%9B%86%E5%92%8C%E5%80%99%E9%80%89%E9%94%AE/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="image" content="/images/avatar.gif">
      <meta itemprop="name" content="鸣蜩十七">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="鸣蜩十七">
      <meta itemprop="description" content="记录我的学习、生活和恋爱日常">
    </span>

    <span hidden itemprop="post" itemscope itemtype="http://schema.org/CreativeWork">
      <meta itemprop="name" content="undefined | 鸣蜩十七">
      <meta itemprop="description" content="">
    </span>
      <header class="post-header">
        <h2 class="post-title" itemprop="name headline">
          <a href="/2023/04/24/%E6%95%B0%E6%8D%AE%E5%BA%93%E5%8E%9F%E7%90%86%EF%BC%9A%E6%B1%82%E6%9C%80%E5%B0%8F%E4%BE%9D%E8%B5%96%E9%9B%86%E5%92%8C%E5%80%99%E9%80%89%E9%94%AE/" class="post-title-link" itemprop="url">数据库原理：求最小依赖集和候选键</a>
        </h2>

        <div class="post-meta-container">
          <div class="post-meta">
    <span class="post-meta-item">
      <span class="post-meta-item-icon">
        <i class="far fa-calendar"></i>
      </span>
      <span class="post-meta-item-text">发表于</span>

      <time title="创建时间：2023-04-24 00:57:03" itemprop="dateCreated datePublished" datetime="2023-04-24T00:57:03+08:00">2023-04-24</time>
    </span>
    <span class="post-meta-item">
      <span class="post-meta-item-icon">
        <i class="far fa-calendar-check"></i>
      </span>
      <span class="post-meta-item-text">更新于</span>
      <time title="修改时间：2023-05-11 21:48:23" itemprop="dateModified" datetime="2023-05-11T21:48:23+08:00">2023-05-11</time>
    </span>
    <span class="post-meta-item">
      <span class="post-meta-item-icon">
        <i class="far fa-folder"></i>
      </span>
      <span class="post-meta-item-text">分类于</span>
        <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
          <a href="/categories/%E6%95%B0%E6%8D%AE%E5%BA%93%E5%8E%9F%E7%90%86/" itemprop="url" rel="index"><span itemprop="name">-数据库原理</span></a>
        </span>
    </span>

  
</div>

        </div>
      </header>

    
    
    
    <div class="post-body" itemprop="articleBody">
          <h1 id="数据库依赖的公理系统"><a href="#数据库依赖的公理系统" class="headerlink" title="数据库依赖的公理系统"></a>数据库依赖的公理系统</h1><h2 id="Armstrong-公理"><a href="#Armstrong-公理" class="headerlink" title="Armstrong 公理"></a>Armstrong 公理</h2><p><strong>Armstrong 公理</strong>规定了以下的推理规则：</p>
<div class="table-container">
<table>
<thead>
<tr>
<th>推理规则</th>
<th>内容</th>
</tr>
</thead>
<tbody>
<tr>
<td>A1 自反律</td>
<td>若 Y⊆X⊆U, 则 X→Y 成立</td>
</tr>
<tr>
<td>A2 增广律</td>
<td>若 Z⊆U 且 X→Y，则 XZ→YZ 成立</td>
</tr>
<tr>
<td>A3 传递律</td>
<td>若 X→Y，Y→Z，则 X→Z 成立</td>
</tr>
</tbody>
</table>
</div>
<p>根据以上三条公理，可得到以下推理规则：</p>
<div class="table-container">
<table>
<thead>
<tr>
<th>推理规则</th>
<th>内容</th>
</tr>
</thead>
<tbody>
<tr>
<td>合并规则</td>
<td>若 X→Y，X→Z，则 X→YZ 成立</td>
</tr>
<tr>
<td>伪传递规则</td>
<td>若 X→Y，WY→Z，则 WX→Z 成立</td>
</tr>
<tr>
<td>分解规则</td>
<td>若 X→Y，且 Z⊆Y，则 X→Z 成立</td>
</tr>
<tr>
<td>复合规则</td>
<td>若 X→Y，且 W→Z，则 XW→ZY 成立</td>
</tr>
</tbody>
</table>
</div>
<p>通过这些推导，我们可以得出关系模式R的所有函数依赖，包括直接和间接的函数依赖。这些函数依赖可以用来判断该关系模式是否符合范式的要求，以及进行范式分解和数据库设计。</p>
<h2 id="函数依赖闭包"><a href="#函数依赖闭包" class="headerlink" title="函数依赖闭包"></a>函数依赖闭包</h2><p>设F为属性集U上的一组函数依赖，X、Y⊆U，$X_F^+={A|X→A能由F根据Armstrong公理导出}$,$X_F^+$称为<strong>属性集X关于函数依赖集F的闭包</strong>。</p>
<p>说人话就是，属性或属性组X的闭包$X_F^+$就是能由X推导出的属性的集合。</p>
<p>例如设属性集 U={A,B,C}，函数依赖集 F={A→B, B→C} 则 AF+={A，B，C}，BF+={B，C}，CF+={C}。</p>
<p>大题的做法如下：</p>
<p>例如，已知关系模式R<u,f>，其中，U={A,B,C,D,E}，F={AB→C,B→D,C→E,EC→B,AC→B}。求$(AB)_F^+$。</u,f></p>
<p><strong>解</strong>    设$X^{(0)}=AB$  <strong>求谁的闭包就设$X^{(0)}$等于谁</strong><br>求$X^{(1)}：$因为AB→C，B→D，所以$X^{(1)}=X^{(0)} \cup CD=AB \cup CD=ABCD$<br><strong>这一步首先在F中找AB($X^{(0)}$)的子集，再用AB($X^{(0)}$)并上找到的函数依赖右边的属性，这就是$X^{(2)}$的值</strong><br>求$X^{(2)}：$因为C→E,AC→B，所以$X^{(2)}=X^{(1)} \cup CD=ABCD \cup BE=ABCDE=U$<br><strong>当$X^{(i+1)}=X^{(i)}$或$X^{(i+1)}=U$时停止，此时的$X^{(i+1)}$就是待求的闭包</strong><br>所以，$(AB)_F^+={ABCDE}$</p>

      
    </div>

    
    
    

    <footer class="post-footer">
        <div class="post-eof"></div>
      
    </footer>
  </article>
</div>




    


<div class="post-block">
  
  

  <article itemscope itemtype="http://schema.org/Article" class="post-content" lang="">
    <link itemprop="mainEntityOfPage" href="http://xiaoqingming18.github.io/2023/04/23/%E6%95%B0%E6%8D%AE%E5%BA%93%E5%8E%9F%E7%90%86%EF%BC%9A%E5%85%B3%E7%B3%BB%E8%A7%84%E8%8C%83%E5%8C%96/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="image" content="/images/avatar.gif">
      <meta itemprop="name" content="鸣蜩十七">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="鸣蜩十七">
      <meta itemprop="description" content="记录我的学习、生活和恋爱日常">
    </span>

    <span hidden itemprop="post" itemscope itemtype="http://schema.org/CreativeWork">
      <meta itemprop="name" content="undefined | 鸣蜩十七">
      <meta itemprop="description" content="">
    </span>
      <header class="post-header">
        <h2 class="post-title" itemprop="name headline">
          <a href="/2023/04/23/%E6%95%B0%E6%8D%AE%E5%BA%93%E5%8E%9F%E7%90%86%EF%BC%9A%E5%85%B3%E7%B3%BB%E8%A7%84%E8%8C%83%E5%8C%96/" class="post-title-link" itemprop="url">数据库原理：关系规范化</a>
        </h2>

        <div class="post-meta-container">
          <div class="post-meta">
    <span class="post-meta-item">
      <span class="post-meta-item-icon">
        <i class="far fa-calendar"></i>
      </span>
      <span class="post-meta-item-text">发表于</span>

      <time title="创建时间：2023-04-23 21:08:01" itemprop="dateCreated datePublished" datetime="2023-04-23T21:08:01+08:00">2023-04-23</time>
    </span>
    <span class="post-meta-item">
      <span class="post-meta-item-icon">
        <i class="far fa-calendar-check"></i>
      </span>
      <span class="post-meta-item-text">更新于</span>
      <time title="修改时间：2023-05-11 21:48:16" itemprop="dateModified" datetime="2023-05-11T21:48:16+08:00">2023-05-11</time>
    </span>
    <span class="post-meta-item">
      <span class="post-meta-item-icon">
        <i class="far fa-folder"></i>
      </span>
      <span class="post-meta-item-text">分类于</span>
        <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
          <a href="/categories/%E6%95%B0%E6%8D%AE%E5%BA%93%E5%8E%9F%E7%90%86/" itemprop="url" rel="index"><span itemprop="name">-数据库原理</span></a>
        </span>
    </span>

  
</div>

        </div>
      </header>

    
    
    
    <div class="post-body" itemprop="articleBody">
          <h1 id="规范化"><a href="#规范化" class="headerlink" title="规范化"></a>规范化</h1><p>规范化是指将一个关系数据库设计转换成一系列符合规范的关系模式（通过分解关系模式来消除其中不合适的数据依赖），以解决插入异常、删除异常、更新异常和数据冗余问题。</p>
<p>在进行规范化时，我们遵循一系列的规则，这些规则被称为科德范式（Codd’s Normal Forms）。科德范式包括一系列的规范化级别，从第一范式（1NF）到第五范式（5NF），每个级别都有一定的规则和要求，用于确保规范化的正确性和有效性。</p>
<p>下面是几个常见的科德范式：</p>
<ol>
<li>第一范式（1NF）：要求每个属性都是原子性的，即每个属性不能再分解为更小的属性。</li>
<li>第二范式（2NF）：要求满足第一范式，并且非主键属性必须完全依赖于主键，即非主键属性不能部分依赖于主键。</li>
<li>第三范式（3NF）：要求满足第二范式，并且非主键属性不依赖于其他非主键属性，即非主键属性不能传递依赖于其他非主键属性。</li>
<li>巴斯-科德范式（BCNF）：要求满足第三范式，并且每个非主键属性必须独立于主键，即非主键属性之间不能存在函数依赖关系。</li>
</ol>
<h1 id="函数依赖"><a href="#函数依赖" class="headerlink" title="函数依赖"></a>函数依赖</h1><h2 id="关系模式的表示"><a href="#关系模式的表示" class="headerlink" title="关系模式的表示"></a>关系模式的表示</h2><p>关系模式的完整表示是一个五元组：<br><code>R〈U，D，Dom，F〉</code><br>其中：</p>
<ul>
<li>R为<strong>关系名</strong>；</li>
<li>U为关系的<strong>属性集合</strong>；</li>
<li>D为属性集U中属性的数据域；</li>
<li>Dom为属性到域的映射；</li>
<li>F为属性集U的<strong>数据依赖集</strong>。<br>关系模式可以用三元组简单表示为：<br><code>R〈U，F〉</code></li>
</ul>
<h2 id="函数依赖的定义"><a href="#函数依赖的定义" class="headerlink" title="函数依赖的定义"></a>函数依赖的定义</h2><p>设关系模式R(U)，U是属性集，X和Y是U的子集。如果对于R(U)的任意一个可能的关系r，r中不可能存在两个元组在X上的属性值相等，而在Y上的属性值不等，则称<strong>X函数确定Y</strong>或<strong>Y函数依赖于X</strong>，记作<strong>X→Y</strong>。</p>
<p>下面介绍一些术语和符号：</p>
<ul>
<li>X→Y，但$Y \nsubseteq X$,则称X→Y是<strong>非平凡的函数依赖</strong>。</li>
<li>X→Y，但$Y \subseteqq X$,则称X→Y是<strong>平凡的函数依赖</strong>。对于任一关系模式，平凡函数依赖总是成立的，所以如果不特别声明，总是讨论非平凡的函数依赖。</li>
<li>若X→Y，则称X为这个函数依赖的决定属性组，也称为<strong>决定因素</strong>。</li>
<li>若X→Y，Y→X，则记作X ↔ Y。</li>
<li>若Y不函数依赖与X，则记作$X \nrightarrow Y$。</li>
</ul>
<p>举个例子，假设有一个关系表包含学生的信息，其中包含学生的姓名、学号和班级。在这个关系表中，学号是一个唯一的标识符，每个学生都有一个唯一的学号。因此，学号决定自身的取值，==这是一个平凡函数依赖==。而学号能够唯一地确定学生的姓名和班级，==这是一个非平凡函数依赖==。</p>
<h2 id="完全函数依赖的定义"><a href="#完全函数依赖的定义" class="headerlink" title="完全函数依赖的定义"></a>完全函数依赖的定义</h2><p>在R(U)中，如果X→Y，并且对于X的任何一个真子集$X’$,都有$X’ \nrightarrow Y$，则称Y对X<strong>完全函数依赖</strong>，记作$X \stackrel{F}{\rightarrow} Y$。</p>
<p>如果X→Y，但Y不完全函数依赖于X，则称Y对X<strong>部分函数依赖</strong>，记作$X \stackrel{F}{\nrightarrow} Y$。</p>
<p>举个例子，$(Sno,Cno) \stackrel{F}{\rightarrow} Grade$是完全函数依赖，$(Sno,Cno) \stackrel{F}{\rightarrow} Sdept$是部分函数依赖，因为Sno→Sdept成立，并且Sno是(Sno，Cno)的真子集。</p>
<h2 id="传递函数依赖的定义"><a href="#传递函数依赖的定义" class="headerlink" title="传递函数依赖的定义"></a>传递函数依赖的定义</h2><p>在R(U)中，如果X→Y（$Y \nsubseteq X$），$Y \nrightarrow X$，Y→Z，$Z \nsubseteq Y$，则称Z对X<strong>传递函数依赖</strong>，记作$X \stackrel{传递}{\rightarrow} Z$。</p>
<p>这里加上条件$Y \nrightarrow X$，是因为如果Y→X，则X ↔ Y，实际上是$X \stackrel{直接}{\rightarrow} Z$，是直接函数依赖而不是传递函数依赖。</p>
<p>举个例子，有Sno→Sdept，Sdept→Mname（Mname为系主任姓名）成立，所以$Sno \stackrel{传递}{\rightarrow} Mname$。</p>
<h2 id="码的定义"><a href="#码的定义" class="headerlink" title="码的定义"></a>码的定义</h2><p>码是关系模式中的一个重要概念，在前面已经给出了码的定义，这里用函数依赖的概念来定义码。</p>
<p>设K为R<u,f>中的属性或属性集合，若$K \stackrel{F}{\rightarrow} U$，则称K为R的<strong>候选码</strong>。如果U函数依赖于K，即K→U，则K称为<strong>超码</strong>。候选码是一类特殊的超码，即候选码的超集（如果存在）一定是超码，而候选码的任何真子集一定不是超码。说人话就是候选码是超码的子集。</u,f></p>
<p>若候选码多于一个，则选定其中一个为<strong>主码</strong>。包含在任何一个候选码中的属性称为<strong>主属性</strong>；不包含在任何候选码中的属性称为<strong>非主属性</strong>或<strong>非码属性</strong>。</p>
<p>下面我们简单的解释一下上面所说的几个概念：</p>
<ul>
<li>什么是码：如果一个属性集合能够决定其他所有属性，那么这个属性集合就是一个码。</li>
<li>什么是候选码：学号是唯一标识学生的属性，因此学号可以作为一个<strong>候选码</strong>。除了学号之外，如果我们把学号和姓名作为属性集合，也能唯一标识学生，因此学号和姓名也是一个<strong>候选码</strong>。</li>
<li>什么是超码：如果我们把学号、姓名和性别作为属性集合，虽然它仍然可以唯一标识学生，但是它已经不是最小的唯一标识学生的属性集合了。因此，学号、姓名和性别是一个<strong>超码</strong>，它包含了候选码学号和姓名，但不是最小的唯一标识学生的属性集合。</li>
</ul>
<p>再说人话，候选码是超码的子集，也可以说超码包含候选码。候选码是最小的能够唯一标识实体的属性集合，而超码是包含候选码的属性集合，可以用来表示实体的其他特征。因此，超码包含了候选码的所有信息，但是也包含了更多的信息。</p>
<h1 id="范式"><a href="#范式" class="headerlink" title="范式"></a>范式</h1><p>在数据库设计中，范式是一种规范化的数据结构设计方法，旨在避免发生插入异常、删除异常和更新异常，并保证数据冗余应尽可能少。范式分为多个级别，每个级别都有其特定的规则和要求。</p>
<h2 id="第一范式"><a href="#第一范式" class="headerlink" title="第一范式"></a>第一范式</h2><p><strong>第一范式（1NF）</strong>是关系型数据库设计中的基本规范，它要求每个属性都是原子性的，即不可分解的。这意味着每个属性都应该包含单一的数据值，而不是一个包含多个值的列表或数组。</p>
<p>具体来说，第一范式要求：</p>
<ol>
<li>属性的值必须是原子性的，即不能再分解为更小的数据单位。例如，一个人的姓名不能被分解为姓和名两个部分，这两个部分应该作为两个独立的属性存储。</li>
<li>每个属性在一个关系中只能出现一次。如果一个属性在一个关系中出现多次，则应该将其拆分为多个独立的属性。</li>
<li>每个属性必须有一个唯一的名称，以便在关系中进行引用。</li>
</ol>
<h2 id="第二范式"><a href="#第二范式" class="headerlink" title="第二范式"></a>第二范式</h2><p><strong>第二范式 （2NF）</strong>的定义是若 R∈1NF，且每一个非主属性完全依赖于 R 的候选码，则 R∈2NF，<strong>2NF 在 1NF 的基础上消除了非主属性对码的部分依赖</strong>。</p>
<p>例如已知学生关系模式，其中 Sno 学号、Sname 姓名、SD 系名、Sdname 系主任名、Course 课程、Grade 成绩。</p>
<figure class="highlight plaintext"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">S(Sno，Sname，SD，Sdname，Course，Grade)</span><br></pre></td></tr></tbody></table></figure>
<p>关系模式S的基本函数依赖如下：</p>
<figure class="highlight plaintext"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Sno→Sname, Sno→SD, SD→Sdname, (Sno，Course)→Grade</span><br></pre></td></tr></tbody></table></figure>
<p>不难看出关系模式S的码为 (Sno，Course)。非主属性中的成绩完全依赖于码，而其它非主属性对码的函数依赖为部分函数依赖，比如，Sdname就部分依赖于码 (Sno，Course)，此时若修改Sdname就要修改每一条包含原Sdname的记录，造成数据冗余。所以不属于 2NF，原关系模式 S 属于 1NF。</p>
<p><img src="/2023/04/23/%E6%95%B0%E6%8D%AE%E5%BA%93%E5%8E%9F%E7%90%86%EF%BC%9A%E5%85%B3%E7%B3%BB%E8%A7%84%E8%8C%83%E5%8C%96/第二范式1.png" alt="第二范式"></p>
<p>此时如果对数据进行增删改查操作就会出问题，例如将所有记录都删除时就会丢失系信息。因此消除非主属性对码的函数依赖为部分函数依赖后，将关系模式分解成 2NF 如下：</p>
<figure class="highlight plaintext"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">SD(Sno, Sname, SD, Sdname)</span><br><span class="line">SC(Sno, Course, Grade) </span><br></pre></td></tr></tbody></table></figure>
<p><img src="/2023/04/23/%E6%95%B0%E6%8D%AE%E5%BA%93%E5%8E%9F%E7%90%86%EF%BC%9A%E5%85%B3%E7%B3%BB%E8%A7%84%E8%8C%83%E5%8C%96/第二范式2.png" alt="第二范式"></p>
<h2 id="第三范式"><a href="#第三范式" class="headerlink" title="第三范式"></a>第三范式</h2><p><strong>第三范式（2NF）</strong>的定义是若 R∈1NF，且每一个非主属性都不传递依赖于 R 的候选码，则 R∈3NF，<strong>3NF 消除了非主属性对码的传递函数依赖</strong>。<br>例如对于上文的关系模式中，关系模式 S1 中存在 Sno→SD，SD→Sdname，即非主属性 Sdname 传递依赖于 Sno，所以 S1 不是 3NF。</p>
<figure class="highlight plaintext"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">SD(Sno, Sname, SD, Sdname)</span><br><span class="line">SC(Sno, Course, Grade) </span><br></pre></td></tr></tbody></table></figure>
<p>此时如果对数据进行增删改查操作就会出问题，例如将所有同学的信息全部删除，就会丢失所有系信息。进一步分解如下，分解后的关系模式 S11、S12 满足 3NF。</p>
<figure class="highlight plaintext"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">S(Sno, Sname, SD)</span><br><span class="line">D(SD, Sdname)</span><br><span class="line">C(Sno, Course, Grade)</span><br></pre></td></tr></tbody></table></figure>
<p><img src="/2023/04/23/%E6%95%B0%E6%8D%AE%E5%BA%93%E5%8E%9F%E7%90%86%EF%BC%9A%E5%85%B3%E7%B3%BB%E8%A7%84%E8%8C%83%E5%8C%96/第三范式.png" alt="第三范式"></p>
<h2 id="BCNF范式"><a href="#BCNF范式" class="headerlink" title="BCNF范式"></a>BCNF范式</h2><p>BCNF 比 3NF 更进了一步，通常认为 BCNF 是修正的第三范式。<strong>BCNF</strong> 的定义是若 R∈1NF，且<strong>每一个非主属性都完全依赖于 R 的候选码，所有的主属性对每一个不包含它的码也是完全函数依赖，没有任何属性完全函数依赖于非码的任何一组属性</strong>，则 R∈BCNF。BCNF 范式排除了任何属性对候选键的传递依赖与部分依赖，而 2NF 和 3NF 都是针对主属性的。<br>例如关系模式 SJP(S,J,P)中，S 是学生，J 表示课程，P 表示名次。每一个学生选修每门课程的成绩有一定的名次，每门课程中每一名次只有一个学生（即没有并列名次）。可得到下面的函数依赖：</p>
<figure class="highlight plaintext"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">F = {(S,J)→P, (J,P)→S}</span><br></pre></td></tr></tbody></table></figure>
<p>可知 (S,J) 与 (J,P) 都可以作为候选码，这两个码各由两个属性组成且相交。这个关系模式中显然没有属性对码传递依赖或部分依赖，所以 SJP∈3NF，而且除 (S,J）与（J,P）以外没有其他决定因素，所以 SJP∈BCNF。<br>看一个不是 BCNF 的例子，例如关系模式 STJ(S,T,J)中，S 表示学生，T 表示教师，J 表示课程。每一教师只教一门课，每门课有若干教师，某一学生选定某门课，就对应一个固定的教师。可得到如下的函数依赖：</p>
<figure class="highlight plaintext"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">F = {(S,J)→T, (S,T)→J, T→J}</span><br></pre></td></tr></tbody></table></figure>
<p>可知 (S, J)、(S, T) 都是候选码，因为没有任何非主属性对码传递依赖或部分依赖，所以 STJ 是 3NF。但 STJ 不是 BCNF，因为 T 是决定因素但是 T 不包含码。</p>

      
    </div>

    
    
    

    <footer class="post-footer">
        <div class="post-eof"></div>
      
    </footer>
  </article>
</div>




    


<div class="post-block">
  
  

  <article itemscope itemtype="http://schema.org/Article" class="post-content" lang="">
    <link itemprop="mainEntityOfPage" href="http://xiaoqingming18.github.io/2023/04/23/%E6%95%B0%E6%8D%AE%E5%BA%93%E5%8E%9F%E7%90%86%EF%BC%9A%E6%95%B0%E6%8D%AE%E6%A8%A1%E5%9E%8B/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="image" content="/images/avatar.gif">
      <meta itemprop="name" content="鸣蜩十七">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="鸣蜩十七">
      <meta itemprop="description" content="记录我的学习、生活和恋爱日常">
    </span>

    <span hidden itemprop="post" itemscope itemtype="http://schema.org/CreativeWork">
      <meta itemprop="name" content="undefined | 鸣蜩十七">
      <meta itemprop="description" content="">
    </span>
      <header class="post-header">
        <h2 class="post-title" itemprop="name headline">
          <a href="/2023/04/23/%E6%95%B0%E6%8D%AE%E5%BA%93%E5%8E%9F%E7%90%86%EF%BC%9A%E6%95%B0%E6%8D%AE%E6%A8%A1%E5%9E%8B/" class="post-title-link" itemprop="url">数据模型</a>
        </h2>

        <div class="post-meta-container">
          <div class="post-meta">
    <span class="post-meta-item">
      <span class="post-meta-item-icon">
        <i class="far fa-calendar"></i>
      </span>
      <span class="post-meta-item-text">发表于</span>

      <time title="创建时间：2023-04-23 19:59:03" itemprop="dateCreated datePublished" datetime="2023-04-23T19:59:03+08:00">2023-04-23</time>
    </span>
    <span class="post-meta-item">
      <span class="post-meta-item-icon">
        <i class="far fa-calendar-check"></i>
      </span>
      <span class="post-meta-item-text">更新于</span>
      <time title="修改时间：2023-05-11 21:48:47" itemprop="dateModified" datetime="2023-05-11T21:48:47+08:00">2023-05-11</time>
    </span>
    <span class="post-meta-item">
      <span class="post-meta-item-icon">
        <i class="far fa-folder"></i>
      </span>
      <span class="post-meta-item-text">分类于</span>
        <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
          <a href="/categories/%E6%95%B0%E6%8D%AE%E5%BA%93%E5%8E%9F%E7%90%86/" itemprop="url" rel="index"><span itemprop="name">-数据库原理</span></a>
        </span>
    </span>

  
</div>

        </div>
      </header>

    
    
    
    <div class="post-body" itemprop="articleBody">
          <h1 id="数据库原理：数据模型与关系模型"><a href="#数据库原理：数据模型与关系模型" class="headerlink" title="数据库原理：数据模型与关系模型"></a>数据库原理：数据模型与关系模型</h1><h2 id="数据模型"><a href="#数据模型" class="headerlink" title="数据模型"></a>数据模型</h2><p>数据模型是一种模型，它是对现实世界数据特征的抽象。数据模型也是数据库系统的核心和基础。</p>
<h3 id="数据模型分类"><a href="#数据模型分类" class="headerlink" title="数据模型分类"></a>数据模型分类</h3><p>第一类是<strong>概念模型</strong>，第二类是<strong>逻辑模型</strong>和<strong>物理模型</strong>。</p>
<p>第一类概念模型也称信息模型。它是按用户的观点来对数据和信息建模，主要用数据库设计。</p>
<p>第二类中的<strong>逻辑模型</strong>主要包括层次模型、网状模型、关系模型、面向对象数据模型和对象关系数据模型、半结构化数据模型等。它是按计算机系统的观点对数据建模，主要用于数据库管理系统的实现。</p>
<p>第二类中的<strong>物理模型</strong>是对数据最底层的抽象，描述数据在系统内部的表示方式和存取方法，是面向计算机系统的。</p>
<p>物理模型的具体实现是数据库管理系统的任务，数据库设计人员要了解和选择物理模型，最终用户不必考虑物理级的细节。</p>
<h3 id="概念模型"><a href="#概念模型" class="headerlink" title="概念模型"></a>概念模型</h3><p>概念模型是现实世界到机器世界的中间一个层次，概念模型用于信息世界的建模。</p>
<h4 id="信息世界中的基本概念"><a href="#信息世界中的基本概念" class="headerlink" title="信息世界中的基本概念"></a>信息世界中的基本概念</h4><p>信息世界主要涉及以下一些概念：</p>
<ol>
<li>实体：客观存在并可相互区别的事物；</li>
<li>属性：实体所具有的某一特性；</li>
<li>码：唯一标识实体的属性集；</li>
<li>实体型：用实体名及其属性名集合来抽象和刻画同类实体。例如，学生（学号，姓名，性别，出生年月，所在院系，入学时间）就是一个实体型；</li>
<li>实体集：同一类型实体的集合；</li>
<li>联系：实体之间的联系通常是指不同实体集之间的联系。实体之间的联系有<strong>一对一</strong>、<strong>一对多</strong>、<strong>多对多</strong>等多种类型。</li>
</ol>
<h4 id="实体之间的联系类型"><a href="#实体之间的联系类型" class="headerlink" title="实体之间的联系类型"></a>实体之间的联系类型</h4><ol>
<li><strong>一对一联系</strong>表示一个实体集中的一个实体只能关联另一个实体集中的一个实体，而且这两个实体之间是一一对应的。举个例子，假设实体集A表示人，实体集B表示身份证，一对一联系表示一个人只能有一个身份证，而且一个身份证只能对应一个人。在这种情况下，一个人和一个身份证之间是一一对应的关系；</li>
<li><strong>一对多联系</strong>表示一个实体集中的一个实体可以关联另一个实体集中的==多个==实体，但是另一个实体集中的一个实体只能关联该实体集中的==一个==实体；举个例子，假设实体集A表示订单，实体集B表示商品，一对多联系表示一个订单可以包含多个商品，而一个商品只属于一个订单；</li>
<li>多对多联系表示一个实体集中的一个实体可以关联另一个实体集中的==多个==实体，而且另一个实体集中的一个实体也可以关联该实体集中的==多个==实体。举个例子，假设实体集A表示学生，实体集B表示课程，多对多联系表示一个学生可以选修多门课程，而一门课程也可以被多名学生选修。在这种情况下，一个学生和一门课程之间是多对多关系。</li>
</ol>
<h2 id="数据模型的组成要素"><a href="#数据模型的组成要素" class="headerlink" title="数据模型的组成要素"></a>数据模型的组成要素</h2><p>数据模型是严格定义的一组概念的集合，用于描述了系统的静态特性、动态特性和完整性约束条件。数据模型通常由数据结构、数据操作和数据的完整性约束条件三部分组成。</p>
<div class="table-container">
<table>
<thead>
<tr>
<th>组成要素</th>
<th>说明</th>
</tr>
</thead>
<tbody>
<tr>
<td>数据结构</td>
<td>描述数据库的组成对象以及对象之间的联系</td>
</tr>
<tr>
<td>数据操作</td>
<td>指对数据库中各种对象（型）的实例（值）允许执行的操作的集合，包括操作及有关的操作规则</td>
</tr>
<tr>
<td>完整性约束条件</td>
<td>是一组完整性规则，给定的数据模型中数据及其联系所具有的制约和依存规则</td>
</tr>
</tbody>
</table>
</div>
<p>简单解释一下这三个组成要素：</p>
<p>数据结构指的是数据库中数据的组织方式，通常采用表格的形式，每个表格包含多个列和多行数据。每个列定义了一个属性，每一行代表一个实例，实例的属性值存储在相应的列中。</p>
<p>数据操作指的是对数据库中数据进行的操作，包括数据的增加、删除、修改和查询等。这些操作可以通过SQL语句来实现，SQL语句可以用于创建表格、插入数据、删除数据、更新数据和查询数据等。</p>
<p>数据的完整性约束条件指的是对数据库中数据进行限制和检查的规则，以确保数据的完整性和一致性。这些规则包括主键约束、外键约束、唯一约束、非空约束等。主键约束用于保证每条记录的唯一性，外键约束用于保证表格间的关系的一致性，唯一约束用于保证某些列的唯一性，非空约束用于保证某些列不允许为空值。</p>
<h2 id="常用的数据模型"><a href="#常用的数据模型" class="headerlink" title="常用的数据模型"></a>常用的数据模型</h2><h3 id="层次模型"><a href="#层次模型" class="headerlink" title="层次模型"></a>层次模型</h3><p>层次模型是数据库中的一种数据组织方式，采用树形结构来表示数据之间的层次关系。在层次模型中，每个节点可以有多个子节点，但是一个节点只能有一个父节点，这种关系被称为“一对多”的层次关系。</p>
<p>例如，一个教师学生层次模型，它有 3 个记录类型，专业是根结点，教师和学生类型是专业的子结点。进行插入操作时，如果没有相应的双亲结点值就不能插入它的子女结点值。进行删除操作时，如果删除双亲结点值，则相应的子女结点值也将被同时删除。</p>
<p><img src="/2023/04/23/%E6%95%B0%E6%8D%AE%E5%BA%93%E5%8E%9F%E7%90%86%EF%BC%9A%E6%95%B0%E6%8D%AE%E6%A8%A1%E5%9E%8B/层次模型.png" alt="层次模型示意图"></p>
<p>层次模型的优点主要有：</p>
<ol>
<li>数据结构比较简单清晰；</li>
<li>查询效率高，层次模型中记录之间的联系用有向边表示；</li>
<li>提供了良好的完整性支持。</li>
</ol>
<p>层次模型的缺点主要有：</p>
<ol>
<li>现实世界中很多联系是非层次性的；</li>
<li>对一个结点具有多个双亲结点等情况表示能力有限；</li>
<li>查询子女结点必须通过双亲结点；</li>
<li>结构严密，层次命令趋于程序化。</li>
</ol>
<p>在实际应用中，层次模型常常被用于管理和组织具有固定层次结构的数据，例如组织机构、分类目录等。但是对于具有复杂关系的数据，关系型数据库和其他数据模型可能更为适合。</p>
<h3 id="网状模型"><a href="#网状模型" class="headerlink" title="网状模型"></a>网状模型</h3><p>与层次模型不同，网状模型中的数据之间可以存在多对多的关系，也就是说，一个实体可以与多个实体相连，一个实体也可以由多个实体相连。这种“多对多”的关系使得网状模型更加灵活，能够更好地适应复杂的数据结构和业务需求。</p>
<p>网状模型满足以下两个条件：</p>
<ol>
<li>允许一个以上的结点无双亲；</li>
<li>一个结点可以有多于一个的双亲；</li>
</ol>
<p>例如一个借书网状模型，一个学生可以借多本书，一本书也可以在不同的时间被不同的同学借走，因此这是一个多对多的联系。学生记录的一个值，借书记录可以有多个值和它对应，但是借书记录的一个值只能和一个学生记录值对应。学生和借书之间是一对多关系，书籍和借书之间也是一对多关系。</p>
<p><img src="/2023/04/23/%E6%95%B0%E6%8D%AE%E5%BA%93%E5%8E%9F%E7%90%86%EF%BC%9A%E6%95%B0%E6%8D%AE%E6%A8%A1%E5%9E%8B/网状模型.png" alt="网状模型示意图"></p>
<h2 id="关系模型"><a href="#关系模型" class="headerlink" title="关系模型"></a>关系模型</h2><p>关系模型建立在严格的数学概念的基础上，是最重要的一种数据模型。在关系模型中，现实世界的实体以及实体间的各种联系均用单一的结构——关系来表示，每个关系的数据结构是一张规范化的二维表。</p>
<p>简单来说，关系模型将数据组织成二维表格的形式，每个表格包含若干行和若干列，行表示记录，列表示字段。表格中的每一列都有一个名称和一个数据类型，用于描述该列所存储的数据的特征。</p>
<p>关系模型中的表格被称为关系，每个关系都具备以下特征：</p>
<ol>
<li>关系是由行和列组成的二维表格；</li>
<li>表格中的每一列都有一个名称和一个数据类型；</li>
<li>表格中的每一行都包含一条记录，每条记录都由若干个字段组成；</li>
<li>每个关系都有一个主键，用于唯一标识每条记录；</li>
<li>关系之间可以通过外键进行关联。</li>
</ol>
<h3 id="关系模型概念"><a href="#关系模型概念" class="headerlink" title="关系模型概念"></a>关系模型概念</h3><div class="table-container">
<table>
<thead>
<tr>
<th>术语</th>
<th>说明</th>
</tr>
</thead>
<tbody>
<tr>
<td>关系</td>
<td>一个关系对应通常说的一张表</td>
</tr>
<tr>
<td>元组</td>
<td>表中的一行即为一个元组</td>
</tr>
<tr>
<td>属性</td>
<td>表中的一列即为一个属性，给每一个属性起一个名称即属性名</td>
</tr>
<tr>
<td>码</td>
<td>也称为码键。表中的某个属性组，它可以唯一确定一个元组</td>
</tr>
<tr>
<td>域</td>
<td>域是一组具有相同数据类型的值的集合，属性的取值范围来自某个域</td>
</tr>
<tr>
<td>分量</td>
<td>元组中的一个属性值</td>
</tr>
<tr>
<td>关系模式</td>
<td>对关系的描述，一般表示为关系名(属性1, 属性2, ……, 属性n)</td>
</tr>
</tbody>
</table>
</div>

      
    </div>

    
    
    

    <footer class="post-footer">
        <div class="post-eof"></div>
      
    </footer>
  </article>
</div>




    


<div class="post-block">
  
  

  <article itemscope itemtype="http://schema.org/Article" class="post-content" lang="">
    <link itemprop="mainEntityOfPage" href="http://xiaoqingming18.github.io/2023/04/23/%E6%95%B0%E6%8D%AE%E5%BA%93%E5%8E%9F%E7%90%86%EF%BC%9ASQL/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="image" content="/images/avatar.gif">
      <meta itemprop="name" content="鸣蜩十七">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="鸣蜩十七">
      <meta itemprop="description" content="记录我的学习、生活和恋爱日常">
    </span>

    <span hidden itemprop="post" itemscope itemtype="http://schema.org/CreativeWork">
      <meta itemprop="name" content="undefined | 鸣蜩十七">
      <meta itemprop="description" content="">
    </span>
      <header class="post-header">
        <h2 class="post-title" itemprop="name headline">
          <a href="/2023/04/23/%E6%95%B0%E6%8D%AE%E5%BA%93%E5%8E%9F%E7%90%86%EF%BC%9ASQL/" class="post-title-link" itemprop="url">SQL笔记</a>
        </h2>

        <div class="post-meta-container">
          <div class="post-meta">
    <span class="post-meta-item">
      <span class="post-meta-item-icon">
        <i class="far fa-calendar"></i>
      </span>
      <span class="post-meta-item-text">发表于</span>

      <time title="创建时间：2023-04-23 13:44:46" itemprop="dateCreated datePublished" datetime="2023-04-23T13:44:46+08:00">2023-04-23</time>
    </span>
    <span class="post-meta-item">
      <span class="post-meta-item-icon">
        <i class="far fa-calendar-check"></i>
      </span>
      <span class="post-meta-item-text">更新于</span>
      <time title="修改时间：2023-05-11 21:49:27" itemprop="dateModified" datetime="2023-05-11T21:49:27+08:00">2023-05-11</time>
    </span>
    <span class="post-meta-item">
      <span class="post-meta-item-icon">
        <i class="far fa-folder"></i>
      </span>
      <span class="post-meta-item-text">分类于</span>
        <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
          <a href="/categories/%E6%95%B0%E6%8D%AE%E5%BA%93%E5%8E%9F%E7%90%86/" itemprop="url" rel="index"><span itemprop="name">-数据库原理</span></a>
        </span>
    </span>

  
</div>

        </div>
      </header>

    
    
    
    <div class="post-body" itemprop="articleBody">
          <h1 id="SQL笔记"><a href="#SQL笔记" class="headerlink" title="SQL笔记"></a>SQL笔记</h1><h2 id="第1课-检索数据"><a href="#第1课-检索数据" class="headerlink" title="第1课 检索数据"></a>第1课 检索数据</h2><h3 id="1-1-检索单个列"><a href="#1-1-检索单个列" class="headerlink" title="1.1 检索单个列"></a>1.1 检索单个列</h3><p>简单的SQL<code>SELECT</code>语句如下：</p>
<figure class="highlight sql"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">SELECT</span> prod_name</span><br><span class="line"><span class="keyword">FROM</span> Products;</span><br></pre></td></tr></tbody></table></figure>
<p>SQL语句不区分大小写，但通常习惯对SQL关键字使用大写，对列表和表名使用小写。</p>
<h3 id="1-2-检索多个列"><a href="#1-2-检索多个列" class="headerlink" title="1.2 检索多个列"></a>1.2 检索多个列</h3><p>要从一个表中检索多个列，可以在<code>SELECT</code>关键字后面给出多个列名，列名之间用逗号分隔。</p>
<p>下面的语句从<code>Products</code>表中选择3列：</p>
<figure class="highlight sql"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">SELECT</span> prod_id,prod_name,prod_price</span><br><span class="line"><span class="keyword">FROM</span> Products;</span><br></pre></td></tr></tbody></table></figure>
<h3 id="1-3-检索所有列"><a href="#1-3-检索所有列" class="headerlink" title="1.3 检索所有列"></a>1.3 检索所有列</h3><p>要检索所有列，可以在实际列名的位置使用星号（*）通配符：</p>
<figure class="highlight sql"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">SELECT</span> <span class="operator">*</span></span><br><span class="line"><span class="keyword">FROM</span> Products;</span><br></pre></td></tr></tbody></table></figure>
<h3 id="1-4-检索不同的值（去除重复值）"><a href="#1-4-检索不同的值（去除重复值）" class="headerlink" title="1.4 检索不同的值（去除重复值）"></a>1.4 检索不同的值（去除重复值）</h3><p>使用<code>DISTINCT</code>关键字可以指示数据库返回不同的值，也即去除重复值：</p>
<figure class="highlight sql"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">SELECT</span> <span class="keyword">DISTINCT</span> vend_id</span><br><span class="line"><span class="keyword">FROM</span> Products;</span><br></pre></td></tr></tbody></table></figure>
<h3 id="1-5-限制结果"><a href="#1-5-限制结果" class="headerlink" title="1.5 限制结果"></a>1.5 限制结果</h3><p>有时可能只想返回第一行或者一定数量的行，各种数据库对这一功能实现的SQL语句不同。</p>
<p>在SQL Server中，可以使用<code>TOP</code>关键字来限制最多返回多少行，如下所示：</p>
<figure class="highlight sql"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">SELECT</span> TOP <span class="number">5</span> prod_name</span><br><span class="line"><span class="keyword">FROM</span> Products;</span><br></pre></td></tr></tbody></table></figure>
<p>上面的代码使用<code>SELECT TOP 5</code>语句，只检索前5行数据。</p>
<h2 id="第2课-排序检索数据"><a href="#第2课-排序检索数据" class="headerlink" title="第2课 排序检索数据"></a>第2课 排序检索数据</h2><h3 id="2-1-排序数据"><a href="#2-1-排序数据" class="headerlink" title="2.1 排序数据"></a>2.1 排序数据</h3><p>使用<code>ORDER BY</code>子句，可以对<code>SELECT</code>语句检索出来的数据进行排序：</p>
<figure class="highlight sql"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">SELECT</span> prod_name</span><br><span class="line"><span class="keyword">FROM</span> Products</span><br><span class="line"><span class="keyword">ORDER</span> <span class="keyword">BY</span> prod_name;</span><br></pre></td></tr></tbody></table></figure>
<p>上面的语句指示DBMS软件对<code>prod_name</code>列以字母顺序排序数据。</p>
<p>要注意的是，<code>ORDER BY</code>子句必须是<code>SELECT</code>语句中的最后一条子句，否则将会出错。</p>
<h3 id="2-2-按多个列排序"><a href="#2-2-按多个列排序" class="headerlink" title="2.2 按多个列排序"></a>2.2 按多个列排序</h3><p><code>ORDER BY</code>子句可以对多个列进行排序，可以在其后给出多个列名，用逗号分隔，并且排列权重从第一个列名往后依次下降。看下面的例子：</p>
<figure class="highlight sql"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">SELECT</span> prod_id,prod_price,prod_name</span><br><span class="line"><span class="keyword">FROM</span> Products</span><br><span class="line"><span class="keyword">ORDER</span> <span class="keyword">BY</span> prod_price,prod_name;</span><br></pre></td></tr></tbody></table></figure>
<p>上面的语句首先按价格排序，然后按名称排序。也即当价格相同时，按名称排序。</p>
<h3 id="2-3-指定排序方向"><a href="#2-3-指定排序方向" class="headerlink" title="2.3 指定排序方向"></a>2.3 指定排序方向</h3><p>数据排序默认升序排序（从A到Z），还可以使用<code>ORDER BY</code>子句进行降序排序。为了进行降序排序，必须指定<code>DESC</code>关键字，下面的例子以价格降序来排序产品：</p>
<figure class="highlight sql"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">SELECT</span> prod_id,prod_price,prod_name</span><br><span class="line"><span class="keyword">FROM</span> Products</span><br><span class="line"><span class="keyword">ORDER</span> <span class="keyword">BY</span> prod_price <span class="keyword">DESC</span>;</span><br></pre></td></tr></tbody></table></figure>
<p>要注意的是，<code>DESC</code>关键字只应用到直接位于其前面的列名，来看下面的例子：</p>
<figure class="highlight sql"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">SELECT</span> prod_id,prod_price,prod_name</span><br><span class="line"><span class="keyword">FROM</span> Products</span><br><span class="line"><span class="keyword">ORDER</span> <span class="keyword">BY</span> prod_price <span class="keyword">DESC</span> prod_name;</span><br></pre></td></tr></tbody></table></figure>
<p>这个例子中，只对产品价格进行降序排序，当产品价格相同时，按产品名称升序排序。</p>
<h3 id="2-4-小结"><a href="#2-4-小结" class="headerlink" title="2.4 小结"></a>2.4 小结</h3><ol>
<li><code>ORDER BY</code>子句必须是<code>SELECT</code>语句中的最后一条子句，否则将会出错；</li>
<li><code>ORDER BY</code>子句可以对多个列进行排序，可以在其后给出多个列名，用逗号分隔，并且排列权重从第一个列名往后依次下降；</li>
<li>在要进行降序排序后面的列名使用<code>DESC</code>关键字，其他列名没有使用<code>DESC</code>关键字则继续默认升序排序。</li>
</ol>
<h2 id="第3课-过滤数据"><a href="#第3课-过滤数据" class="headerlink" title="第3课 过滤数据"></a>第3课 过滤数据</h2><h3 id="3-1-WHERE子句"><a href="#3-1-WHERE子句" class="headerlink" title="3.1 WHERE子句"></a>3.1 WHERE子句</h3><p>在<code>SELECT</code>语句中，数据根据<code>WHERE</code>子句中指定的搜索条件进行过滤，<code>WHERE</code>子句在表名（<code>FROM</code>子句）之后给出，看下面的例子：</p>
<figure class="highlight sql"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">SELECT</span> prod_name,prod_price</span><br><span class="line"><span class="keyword">FROM</span> Products</span><br><span class="line"><span class="keyword">WHERE</span> prod_price <span class="operator">=</span> <span class="number">3.94</span>;</span><br></pre></td></tr></tbody></table></figure>
<p>上面的语句从<code>Products</code>表中返回价格为3.94的行。</p>
<h3 id="3-2-WHERE子句操作符"><a href="#3-2-WHERE子句操作符" class="headerlink" title="3.2 WHERE子句操作符"></a>3.2 WHERE子句操作符</h3><div class="table-container">
<table>
<thead>
<tr>
<th>操作符</th>
<th>说明</th>
<th>操作符</th>
<th>说明</th>
</tr>
</thead>
<tbody>
<tr>
<td>=</td>
<td>等于</td>
<td>&gt;</td>
<td>大于</td>
</tr>
<tr>
<td>&lt;&gt;</td>
<td>不等于</td>
<td>&gt;=</td>
<td>大于等于</td>
</tr>
<tr>
<td>!=</td>
<td>不等于</td>
<td>!&gt;</td>
<td>不大于</td>
</tr>
<tr>
<td>&lt;</td>
<td>小于</td>
<td>BETWEEN</td>
<td>在指定的两个值中间</td>
</tr>
<tr>
<td>&lt;=</td>
<td>小于等于</td>
<td>IS NULL</td>
<td>为NULL值</td>
</tr>
<tr>
<td>!&lt;</td>
<td>不小于</td>
<td></td>
</tr>
</tbody>
</table>
</div>
<h4 id="3-2-1-检查单个值"><a href="#3-2-1-检查单个值" class="headerlink" title="3.2.1 检查单个值"></a>3.2.1 检查单个值</h4><p>列出所有价格小于10元的产品：</p>
<figure class="highlight sql"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">SELECT</span> prod_name,prod_price</span><br><span class="line"><span class="keyword">FROM</span> Products</span><br><span class="line"><span class="keyword">WHERE</span> prod_price <span class="operator">&lt;</span> <span class="number">10</span>;</span><br></pre></td></tr></tbody></table></figure>
<h4 id="3-2-2-不匹配检查"><a href="#3-2-2-不匹配检查" class="headerlink" title="3.2.2 不匹配检查"></a>3.2.2 不匹配检查</h4><p>列出所有不是供应商DLL01制造的产品：</p>
<figure class="highlight sql"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">SELECT</span> vend_id,prod_name</span><br><span class="line"><span class="keyword">FROM</span> Products</span><br><span class="line"><span class="keyword">WHERE</span> vend_id <span class="operator">&lt;&gt;</span> <span class="string">'DLL01'</span>;</span><br></pre></td></tr></tbody></table></figure>
<h4 id="3-2-3-范围值检查"><a href="#3-2-3-范围值检查" class="headerlink" title="3.2.3 范围值检查"></a>3.2.3 范围值检查</h4><p>要检查某个范围的值，可以使用<code>BETWEEN</code>操作符。</p>
<p>检索价格在5元和10元之间的所有产品：</p>
<figure class="highlight sql"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">SELECT</span> prod_name,prod_price</span><br><span class="line"><span class="keyword">FROM</span> Products</span><br><span class="line"><span class="keyword">WHERE</span> prod_price <span class="keyword">BETWEEN</span> <span class="number">5</span> <span class="keyword">AND</span> <span class="number">10</span>;</span><br></pre></td></tr></tbody></table></figure>
<p>从上面的例子可以看出，范围两个值用<code>AND</code>关键字隔开，并且检索结果包括指定的开始值和结束值。</p>
<h4 id="3-2-4-空值检查"><a href="#3-2-4-空值检查" class="headerlink" title="3.2.4 空值检查"></a>3.2.4 空值检查</h4><p>返回没有价格的产品：</p>
<figure class="highlight sql"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">SELECT</span> prod_name</span><br><span class="line"><span class="keyword">FROM</span> Products</span><br><span class="line"><span class="keyword">WHERE</span> prod_price <span class="keyword">IS</span> <span class="keyword">NULL</span>;</span><br></pre></td></tr></tbody></table></figure>
<h2 id="第4课-高级数据过滤"><a href="#第4课-高级数据过滤" class="headerlink" title="第4课 高级数据过滤"></a>第4课 高级数据过滤</h2><h3 id="4-1-组合WHERE子句"><a href="#4-1-组合WHERE子句" class="headerlink" title="4.1 组合WHERE子句"></a>4.1 组合WHERE子句</h3><p>SQL允许给出多个<code>WHERE</code>子句，这些子句可以通过<code>AND</code>或<code>OR</code>操作符使用。</p>
<h4 id="4-1-1-AND操作符"><a href="#4-1-1-AND操作符" class="headerlink" title="4.1.1 AND操作符"></a>4.1.1 AND操作符</h4><p>如果有多个过滤条件，可以使用<code>AND</code>操作符给<code>WHERE</code>子句附加条件，用<code>AND</code>分隔多个条件：</p>
<figure class="highlight sql"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">SELECT</span> prod_id,prod_price,prod_name</span><br><span class="line"><span class="keyword">FROM</span> Products</span><br><span class="line"><span class="keyword">WHERE</span> vend_id <span class="operator">=</span> <span class="string">'DLL01'</span> <span class="keyword">AND</span> prod_priece <span class="operator">&lt;=</span> <span class="number">4</span>;</span><br></pre></td></tr></tbody></table></figure>
<p>上面的SQL语句检索由供应商DLL01制造且价格小于等于4元的所有产品。</p>
<h4 id="4-1-2-OR操作符"><a href="#4-1-2-OR操作符" class="headerlink" title="4.1.2 OR操作符"></a>4.1.2 OR操作符</h4><p><code>OR</code>操作符与<code>AND</code>操作符相反，用<code>OR</code>操作符分隔的多个条件只要满足一个即可：</p>
<figure class="highlight sql"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">SELECT</span> prod_id,prod_price,prod_name</span><br><span class="line"><span class="keyword">FROM</span> Products</span><br><span class="line"><span class="keyword">WHERE</span> vend_id <span class="operator">=</span> <span class="string">'DLL01'</span> <span class="keyword">OR</span> vend_id <span class="operator">=</span> <span class="string">'BRS01'</span>;</span><br></pre></td></tr></tbody></table></figure>
<p>上面的SQL语句检索由DLL01或BRS01供应商制造的所有产品。</p>
<h4 id="4-1-3-求值顺序"><a href="#4-1-3-求值顺序" class="headerlink" title="4.1.3 求值顺序"></a>4.1.3 求值顺序</h4><p>当<code>WHERE</code>子句包含多个<code>AND</code>和<code>OR</code>操作符时，会优先处理<code>AND</code>操作符，我们可以用圆括号对操作符进行明确分组，来看下面的例子：</p>
<figure class="highlight sql"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">SELECT</span> prod_name,prod_name</span><br><span class="line"><span class="keyword">FROM</span> Products</span><br><span class="line"><span class="keyword">WHERE</span> (vend_id <span class="operator">=</span> <span class="string">'DLL91'</span> <span class="keyword">OR</span> vend_id <span class="operator">=</span> <span class="string">'BRS01'</span>)</span><br><span class="line">	<span class="keyword">AND</span> prod_price <span class="operator">&gt;=</span> <span class="number">10</span>;</span><br></pre></td></tr></tbody></table></figure>
<h3 id="4-2-IN操作符"><a href="#4-2-IN操作符" class="headerlink" title="4.2 IN操作符"></a>4.2 IN操作符</h3><p><code>IN</code>操作符用来指定条件范围，范围中的每个条件都可以进行匹配。<code>IN</code>取一组由逗号分隔、括在圆括号里的合法值。</p>
<p>看下面的例子：</p>
<figure class="highlight sql"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">SELECT</span> prod_name,prod_price</span><br><span class="line"><span class="keyword">FROM</span> Products</span><br><span class="line"><span class="keyword">WHERE</span> vend_id <span class="keyword">IN</span> (<span class="string">'DLL01'</span>,<span class="string">'BRS01'</span>)</span><br><span class="line"><span class="keyword">ORDER</span> <span class="keyword">BY</span> prod_name;</span><br></pre></td></tr></tbody></table></figure>
<h3 id="4-3-NOT操作符"><a href="#4-3-NOT操作符" class="headerlink" title="4.3 NOT操作符"></a>4.3 NOT操作符</h3><p><code>NOT</code>操作符用于否定其后所跟的任何条件，要放在列名前面：</p>
<figure class="highlight sql"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">SELECT</span> prod_name</span><br><span class="line"><span class="keyword">FROM</span> Products</span><br><span class="line"><span class="keyword">WHERE</span> <span class="keyword">NOT</span> vend_id <span class="operator">=</span> <span class="string">'DLL01'</span></span><br><span class="line"><span class="keyword">ORDER</span> <span class="keyword">BY</span> prod_name;</span><br></pre></td></tr></tbody></table></figure>
<h2 id="第5课-用通配符进行过滤"><a href="#第5课-用通配符进行过滤" class="headerlink" title="第5课 用通配符进行过滤"></a>第5课 用通配符进行过滤</h2><h3 id="5-1-LIKE操作符"><a href="#5-1-LIKE操作符" class="headerlink" title="5.1 LIKE操作符"></a>5.1 LIKE操作符</h3><p>可以使用<code>LIKE</code>操作符在搜索子句中使用通配符进行模糊匹配。</p>
<h4 id="5-1-1-百分号-通配符"><a href="#5-1-1-百分号-通配符" class="headerlink" title="5.1.1 百分号%通配符"></a>5.1.1 百分号%通配符</h4><p>%表示任何字符出现任意次数。</p>
<p>例如查找所有以词Fish起头的产品：</p>
<figure class="highlight sql"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">SELECT</span> prod_id,prod_name</span><br><span class="line"><span class="keyword">FROM</span> Products</span><br><span class="line"><span class="keyword">WHERE</span> prod_name <span class="keyword">LIKE</span> <span class="string">'Fish%'</span>;</span><br></pre></td></tr></tbody></table></figure>
<p>需要特别注意，%还能匹配0个字符。</p>
<h4 id="5-1-2-下划线-通配符"><a href="#5-1-2-下划线-通配符" class="headerlink" title="5.1.2 下划线_通配符"></a>5.1.2 下划线_通配符</h4><p>下划线_只匹配单个任意字符。</p>
<h4 id="5-1-3-方括号-通配符"><a href="#5-1-3-方括号-通配符" class="headerlink" title="5.1.3 方括号[ ]通配符"></a>5.1.3 方括号[ ]通配符</h4><p>方括号[ ]用来指定一个字符集，它必须匹配指定位置（通配符位置）的一个字符。简单来说，方括号内的多个字符只需要匹配一个即可。</p>
<p>例如，找出所有名字以J或M开头的联系人：</p>
<figure class="highlight sql"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">SELECT</span> cust_contact</span><br><span class="line"><span class="keyword">FROM</span> Customers</span><br><span class="line"><span class="keyword">WHERE</span> cust_contact <span class="keyword">LIKE</span> <span class="string">'[JM]%'</span></span><br></pre></td></tr></tbody></table></figure>
<h2 id="第6课-创建计算字段"><a href="#第6课-创建计算字段" class="headerlink" title="第6课 创建计算字段"></a>第6课 创建计算字段</h2><h3 id="6-1-计算字段"><a href="#6-1-计算字段" class="headerlink" title="6.1 计算字段"></a>6.1 计算字段</h3><p>计算字段并不实际存在于数据库表中，计算字段是运行时在<code>SELECT</code>语句内创建的。</p>
<h3 id="6-2-拼接字段"><a href="#6-2-拼接字段" class="headerlink" title="6.2 拼接字段"></a>6.2 拼接字段</h3><p>要拼接字段，可以使用<code>+</code>或<code>||</code>表示，SQL Server中使用<code>+</code>来拼接字段。</p>
<p>例如，要在输出供应商名称的同时输出他们的位置：</p>
<figure class="highlight sql"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">SELECT</span> vend_name <span class="operator">+</span> <span class="string">'('</span> <span class="operator">+</span> vend_country <span class="operator">+</span> <span class="string">')'</span></span><br><span class="line"><span class="keyword">FROM</span> Vendors</span><br><span class="line"><span class="keyword">ORDER</span> <span class="keyword">BY</span> vend_name;</span><br></pre></td></tr></tbody></table></figure>
<h3 id="6-3-使用别名"><a href="#6-3-使用别名" class="headerlink" title="6.3 使用别名"></a>6.3 使用别名</h3><p>别名用<code>AS</code>关键字赋予，看下面的例子：</p>
<figure class="highlight sql"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">SELECT</span> vend_name <span class="operator">+</span> <span class="string">'('</span> <span class="operator">+</span> vend_country <span class="operator">+</span> <span class="string">')'</span> <span class="keyword">AS</span> vend_title</span><br><span class="line"><span class="keyword">FROM</span> Vendors</span><br><span class="line"><span class="keyword">ORDER</span> <span class="keyword">BY</span> vend_name;</span><br></pre></td></tr></tbody></table></figure>
<h3 id="6-4-执行算数计算"><a href="#6-4-执行算数计算" class="headerlink" title="6.4 执行算数计算"></a>6.4 执行算数计算</h3><p>可以在<code>SELECT</code>语句中使用加（+）减（-）乘（*）除（/）运算。</p>
<p>例如，输出某一个订单中的所有商品信息及每类商品总价：</p>
<figure class="highlight sql"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">SELECT</span> prod_id,quantity,item_price,quantity<span class="operator">*</span>item_price <span class="keyword">AS</span> expanded_price</span><br><span class="line"><span class="keyword">FROM</span> OrderItems</span><br><span class="line"><span class="keyword">WHERE</span> order_num <span class="operator">=</span> <span class="number">20008</span>;</span><br></pre></td></tr></tbody></table></figure>
<p>上面语句中的<code>expanded_price</code>列是一个计算字段。</p>
<h2 id="第7课-使用函数处理数据"><a href="#第7课-使用函数处理数据" class="headerlink" title="第7课 使用函数处理数据"></a>第7课 使用函数处理数据</h2><h2 id="第8课-分组数据"><a href="#第8课-分组数据" class="headerlink" title="第8课 分组数据"></a>第8课 分组数据</h2><h2 id="8-1-创建分组"><a href="#8-1-创建分组" class="headerlink" title="8.1 创建分组"></a>8.1 创建分组</h2><p>分组是使用<code>SELECT</code>语句的<code>GROUP BY</code>子句建立的，来看下面的例子：</p>
<figure class="highlight sql"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">SELECT</span> vend_id,<span class="built_in">COUNT</span>(<span class="operator">*</span>) <span class="keyword">AS</span> num_prods</span><br><span class="line"><span class="keyword">FROM</span> Products</span><br><span class="line"><span class="keyword">GROUP</span> <span class="keyword">BY</span> vend_id;</span><br></pre></td></tr></tbody></table></figure>

      
    </div>

    
    
    

    <footer class="post-footer">
        <div class="post-eof"></div>
      
    </footer>
  </article>
</div>




    


<div class="post-block">
  
  

  <article itemscope itemtype="http://schema.org/Article" class="post-content" lang="">
    <link itemprop="mainEntityOfPage" href="http://xiaoqingming18.github.io/2023/04/09/Javasript%E9%AB%98%E7%BA%A7%E7%A8%8B%E5%BA%8F%E8%AE%BE%E8%AE%A1%E8%AF%BB%E4%B9%A6%E7%AC%94%E8%AE%B0/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="image" content="/images/avatar.gif">
      <meta itemprop="name" content="鸣蜩十七">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="鸣蜩十七">
      <meta itemprop="description" content="记录我的学习、生活和恋爱日常">
    </span>

    <span hidden itemprop="post" itemscope itemtype="http://schema.org/CreativeWork">
      <meta itemprop="name" content="undefined | 鸣蜩十七">
      <meta itemprop="description" content="">
    </span>
      <header class="post-header">
        <h2 class="post-title" itemprop="name headline">
          <a href="/2023/04/09/Javasript%E9%AB%98%E7%BA%A7%E7%A8%8B%E5%BA%8F%E8%AE%BE%E8%AE%A1%E8%AF%BB%E4%B9%A6%E7%AC%94%E8%AE%B0/" class="post-title-link" itemprop="url">Javasript高级程序设计(红宝书)读书笔记</a>
        </h2>

        <div class="post-meta-container">
          <div class="post-meta">
    <span class="post-meta-item">
      <span class="post-meta-item-icon">
        <i class="far fa-calendar"></i>
      </span>
      <span class="post-meta-item-text">发表于</span>

      <time title="创建时间：2023-04-09 23:02:22" itemprop="dateCreated datePublished" datetime="2023-04-09T23:02:22+08:00">2023-04-09</time>
    </span>
    <span class="post-meta-item">
      <span class="post-meta-item-icon">
        <i class="far fa-calendar-check"></i>
      </span>
      <span class="post-meta-item-text">更新于</span>
      <time title="修改时间：2023-04-12 21:28:31" itemprop="dateModified" datetime="2023-04-12T21:28:31+08:00">2023-04-12</time>
    </span>

  
</div>

        </div>
      </header>

    
    
    
    <div class="post-body" itemprop="articleBody">
          <h1 id="JavaScript高级程序设计（红宝书）读书笔记"><a href="#JavaScript高级程序设计（红宝书）读书笔记" class="headerlink" title="JavaScript高级程序设计（红宝书）读书笔记"></a>JavaScript高级程序设计（红宝书）读书笔记</h1><h2 id="bookmark-tabs-第六章-集合引用类型"><a href="#bookmark-tabs-第六章-集合引用类型" class="headerlink" title=":bookmark_tabs:第六章 集合引用类型"></a><span class="github-emoji"><span>📑</span><img src="https://github.githubassets.com/images/icons/emoji/unicode/1f4d1.png?v8" aria-hidden="true" onerror="this.parent.classList.add('github-emoji-fallback')"></span>第六章 集合引用类型</h2><p>[<span class="github-emoji"><span>✒</span><img src="https://github.githubassets.com/images/icons/emoji/unicode/2712.png?v8" aria-hidden="true" onerror="this.parent.classList.add('github-emoji-fallback')"></span>本章内容] </p>
<ol>
<li>对象</li>
<li>数组与定型数组</li>
<li><code>Map</code>、<code>WeakMap</code>、<code>Set</code>以及<code>WeakSet</code>类型</li>
</ol>
<h3 id="page-with-curl-6-1-Object"><a href="#page-with-curl-6-1-Object" class="headerlink" title=":page_with_curl: 6.1 Object"></a><span class="github-emoji"><span>📃</span><img src="https://github.githubassets.com/images/icons/emoji/unicode/1f4c3.png?v8" aria-hidden="true" onerror="this.parent.classList.add('github-emoji-fallback')"></span> 6.1 Object</h3><p><code>Object</code>是<code>ECMAScript</code>中最常用的类型之一。显式地创建<code>Object</code>的实例有两种方式。第一种是使用<code>new</code>操作符和<code>Object</code>构造函数，如下所示：</p>
<figure class="highlight javascript"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> person = <span class="keyword">new</span> <span class="title class_">Object</span>();</span><br><span class="line">person.<span class="property">name</span> = <span class="string">"Nicholas"</span>;</span><br><span class="line">person.<span class="property">age</span> = <span class="number">28</span>;</span><br></pre></td></tr></tbody></table></figure>
<p>另一种方式是使用<strong>对象字面量</strong>表示法。对象字面量是对象定义的简写形式，定义方式如下：</p>
<figure class="highlight javascript"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> person = {</span><br><span class="line">    <span class="attr">name</span>: <span class="string">"Nicholas"</span>,</span><br><span class="line">    <span class="attr">age</span>: <span class="number">28</span></span><br><span class="line">};</span><br><span class="line"><span class="comment">// 属性之间用逗号隔开，最后一个属性后面没有逗号</span></span><br></pre></td></tr></tbody></table></figure>
<p>在对象字面量表示法中，<font color="#dd0000">属性名可以是字符串或数值，</font>比如：</p>
<figure class="highlight javascript"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> person = {</span><br><span class="line">    <span class="string">"name"</span>: <span class="string">"Nicholas"</span>,</span><br><span class="line">    <span class="string">"age"</span>: <span class="number">28</span></span><br><span class="line">    <span class="number">5</span>: <span class="literal">true</span></span><br><span class="line">};</span><br></pre></td></tr></tbody></table></figure>
<p>要注意的是，<font color="#dd0000">数值属性会自动转换为字符串。</font></p>
<p>对象字面量也成为了给函数传递大量可选参数的主要方式，如下：</p>
<figure class="highlight javascript"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">displayInfo</span>(<span class="params">args</span>) {</span><br><span class="line">    <span class="keyword">let</span> output = <span class="string">""</span>;</span><br><span class="line">    <span class="keyword">if</span>(<span class="keyword">typeof</span> args.<span class="property">name</span> == <span class="string">"string"</span>) {</span><br><span class="line">        output += <span class="string">"Name: "</span> + args.<span class="property">name</span> + <span class="string">"\n"</span>;</span><br><span class="line">    }</span><br><span class="line">    <span class="keyword">if</span>(<span class="keyword">typeof</span> args.<span class="property">age</span> == <span class="string">"number"</span>) {</span><br><span class="line">        output += <span class="string">"Age: "</span> + args.<span class="property">age</span> + <span class="string">"\n"</span>;</span><br><span class="line">    }</span><br><span class="line">    <span class="title function_">alert</span>(output);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="title function_">displayInfo</span>(</span><br><span class="line">    <span class="attr">name</span>: <span class="string">"Nicholas"</span>,</span><br><span class="line">    <span class="attr">age</span>: <span class="number">28</span></span><br><span class="line">);</span><br><span class="line"><span class="title function_">displayInfo</span>(</span><br><span class="line">    <span class="attr">name</span>: <span class="string">"Gerg"</span></span><br><span class="line">);</span><br></pre></td></tr></tbody></table></figure>
<p>对象的属性一般用<strong>点语法</strong>来存取，但也可以使用中括号来存取属性，在使用中括号存取属性时，要在括号内使用属性名的字符串形式，比如：</p>
<figure class="highlight javascript"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(person[<span class="string">"name"</span>]);</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(person[<span class="string">"age"</span>]);</span><br></pre></td></tr></tbody></table></figure>
<p>从功能上看，<font color="#006600">两种存取方式没有任何区别，</font><font color="#dd0000">使用中括号存取属性的优势是可以通过变量访问属性，</font>看下面的例子：</p>
<figure class="highlight javascript"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> propertyName = <span class="string">"name"</span>;</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(person[propertyName]); <span class="comment">// "Nicholas"</span></span><br></pre></td></tr></tbody></table></figure>
<p>总结一下，<font color="#dd0000">点语法是首选的属性存取方式，</font>除非访问属性时必须使用变量。</p>
<h3 id="page-with-curl-6-2-Array"><a href="#page-with-curl-6-2-Array" class="headerlink" title=":page_with_curl:6.2 Array"></a><span class="github-emoji"><span>📃</span><img src="https://github.githubassets.com/images/icons/emoji/unicode/1f4c3.png?v8" aria-hidden="true" onerror="this.parent.classList.add('github-emoji-fallback')"></span>6.2 Array</h3><p>除了<code>Object</code>，<code>Array</code>是<code>ECMAScript</code>中最常用的类型了，<code>ECMAScript</code>数组与其他语言的数组最大不得不同是，<font color="#dd0000"><code>ECMAScript</code>数组每个槽位可以存储不同类型的数据，且数组是动态大小的，会随着数据添加自动增长。</font></p>
<h4 id="创建数组"><a href="#创建数组" class="headerlink" title="创建数组"></a>创建数组</h4><p>有几种基本的方式可以创建数组，一种是使用Array构造函数：</p>
<figure class="highlight javascript"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> colors = <span class="keyword">new</span> <span class="title class_">Array</span>();</span><br></pre></td></tr></tbody></table></figure>
<p>还可以给构造函数传一个数值，用来设定数组初始大小：</p>
<figure class="highlight javascript"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> colors = <span class="keyword">new</span> <span class="title class_">Array</span>(<span class="number">20</span>); <span class="comment">// 创建一个初始length为20的color数组</span></span><br></pre></td></tr></tbody></table></figure>
<p>还可以给构造函数传入要保存的元素：</p>
<figure class="highlight javascript"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> colors = <span class="keyword">new</span> <span class="title class_">Array</span>(<span class="string">"red"</span>,<span class="string">"blue"</span>,<span class="string">"green"</span>);</span><br></pre></td></tr></tbody></table></figure>
<font color="#dd0000">在使用`构造函数`时，可以省略`new`操作符。</font>

<p>另一种创建数组的方式是使用<strong>数组字面量</strong>表示法：</p>
<figure class="highlight javascript"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> colors = [<span class="string">"red"</span>,<span class="string">"blue"</span>,<span class="string">"green"</span>]; <span class="comment">// 创建一个包含3个元素的数组</span></span><br><span class="line"><span class="keyword">let</span> names = []; <span class="comment">// 创建一个空数组</span></span><br><span class="line"><span class="keyword">let</span> values = [<span class="number">1</span>,<span class="number">2</span>,]; <span class="comment">// 创建一个包含2个元素的数组</span></span><br></pre></td></tr></tbody></table></figure>
<h4 id="类数组结构转换为数组"><a href="#类数组结构转换为数组" class="headerlink" title="类数组结构转换为数组"></a>类数组结构转换为数组</h4><p><code>Array</code>构造函数有两个<code>ES6</code>新增的用于创建数组的静态方法：<code>from()</code>和<code>of()</code>。</p>
<p><code>from()</code>用于将类数组结构转换为数组实例，而<code>of()</code>用于将一组参数转换为数组实例。下面我们分别讲解下两个方法的用法。</p>
<p>首先来看<code>from()</code>，<code>Array.from()</code>的第一个参数是一个类数组对象，即任何可迭代的结构：</p>
<figure class="highlight javascript"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 字符串会被拆分为单字符数组</span></span><br><span class="line">consoloe.<span class="title function_">log</span>(<span class="title class_">Array</span>.<span class="title function_">from</span>(<span class="string">"吴君丽"</span>)); <span class="comment">// ["吴","君","丽"]</span></span><br><span class="line"></span><br><span class="line"><span class="comment">//对现有数组进行浅复制</span></span><br><span class="line"><span class="keyword">const</span> a1 = [<span class="number">1</span>,<span class="number">2</span>,<span class="number">3</span>,<span class="number">4</span>];</span><br><span class="line"><span class="keyword">const</span> a2 = <span class="title class_">Array</span>.<span class="title function_">from</span>(a1);</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(a2); <span class="comment">// [1,2,3,4]</span></span><br><span class="line"><span class="title function_">alert</span>(a1 == a1); <span class="comment">// false</span></span><br></pre></td></tr></tbody></table></figure>
<p>要注意的是，<font color="#dd0000">利用<code>from()</code>进行浅复制的数组和原数组是不相等的。</font></p>
<p><code>Array.from()</code>好接受第二个可选的映射函数参数，用来改变新数组的值；还可以接收第三个可选的参数，用于指定映射函数中<code>this</code>的值。但这个重写的<code>this</code>值在箭头函数中不适用：</p>
<figure class="highlight javascript"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> a1 = [<span class="number">1</span>,<span class="number">2</span>,<span class="number">3</span>,<span class="number">4</span>];</span><br><span class="line"><span class="keyword">const</span> a2 = <span class="title class_">Array</span>.<span class="title function_">from</span>(a1,x -&gt; x**<span class="number">2</span>);</span><br><span class="line">conse a3 = <span class="title class_">Array</span>.<span class="title function_">from</span>(a1,<span class="keyword">function</span>(<span class="params">x</span>) {<span class="keyword">return</span> x**<span class="variable language_">this</span>.<span class="property">exponent</span>},{<span class="attr">exponment</span>: <span class="number">2</span>});</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(a2); <span class="comment">// [1,4,9,16]</span></span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(a3); <span class="comment">// [1,4,9,16]</span></span><br></pre></td></tr></tbody></table></figure>
<p>最后来看<code>Array.of()</code>，这个方法可以把一组参数转换为数组：</p>
<figure class="highlight javascript"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="title class_">Array</span>.<span class="title function_">of</span>(<span class="number">1</span>,<span class="number">2</span>,<span class="number">3</span>,<span class="number">4</span>)); <span class="comment">// [1,2,3,4]</span></span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="title class_">Array</span>.<span class="title function_">of</span>(<span class="literal">undefined</span>)); <span class="comment">// [undefined]</span></span><br></pre></td></tr></tbody></table></figure>
<h4 id="数组空位"><a href="#数组空位" class="headerlink" title="数组空位"></a>数组空位</h4><p>使用数组字面量初始化数组时，可以使用一串逗号来创建空位。<code>ECMAScript</code>会将逗号之间相应索引位置的值当成空位，可以像下面这样创建一个空位数组：</p>
<figure class="highlight javascript"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> options = [,,,,,]; <span class="comment">//创建包含5个元素的数组</span></span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(options.<span class="property">length</span>); <span class="comment">// 5</span></span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(options) <span class="comment">// [,,,,,]</span></span><br></pre></td></tr></tbody></table></figure>
<font color="#dd0000">在`ES6`中将这些空位当成存在的元素，只不过值为`undefined`。</font>

<h4 id="数组索引"><a href="#数组索引" class="headerlink" title="数组索引"></a>数组索引</h4><p>如果把一个值设置给超过数组最大索引的位置，则数组会自动扩展到该索引值加1。</p>
<p>数组的<code>length</code>数值不是只读的，通过修改<code>length</code>属性，可以从数组末尾删除或添加元素：</p>
<figure class="highlight javascript"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> colors = [<span class="string">"red"</span>,<span class="string">"blue"</span>,<span class="string">"green"</span>];</span><br><span class="line">colors.<span class="property">length</span> = <span class="number">2</span>;</span><br><span class="line"><span class="title function_">alert</span>(colors[<span class="number">2</span>]) <span class="comment">// undefined</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> names = [<span class="string">"小清明"</span>，<span class="string">"吴君丽"</span>,<span class="string">"吴大孬"</span>];</span><br><span class="line">names.<span class="property">length</span> = <span class="number">4</span>;</span><br><span class="line"><span class="title function_">alert</span>(names[<span class="number">3</span>]); <span class="comment">// undefined</span></span><br></pre></td></tr></tbody></table></figure>
<p>使用<code>length</code>属性可以方便的从数组末尾添加元素：</p>
<figure class="highlight javascript"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> colorss = [<span class="string">"red"</span>,<span class="string">"blue"</span>,<span class="string">"green"</span>];</span><br><span class="line">colors[colors.<span class="property">length</span>] = <span class="string">"black"</span></span><br><span class="line">colors[colors.<span class="property">length</span>] = <span class="string">"brown"</span>;</span><br></pre></td></tr></tbody></table></figure>
<p><code>length</code>属性始终会被更新为位置上加上1：</p>
<figure class="highlight javascript"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> colors = [<span class="string">"red"</span>,<span class="string">"blue"</span>,<span class="string">"green"</span>];</span><br><span class="line">colors[<span class="number">99</span>] = <span class="string">"black"</span>;</span><br><span class="line"><span class="title function_">alert</span>(colors.<span class="property">length</span>); <span class="comment">// 100</span></span><br></pre></td></tr></tbody></table></figure>
<p>上面的代码中，<code>colors</code>数组有一个值被插入到位置99，结果<code>length</code>属性被更新为100（99+1），中间所有元素实际上并不存在，所以被访问时会返回<code>undefined</code>。</p>
<h4 id="检测数组"><a href="#检测数组" class="headerlink" title="检测数组"></a>检测数组</h4><p><code>Array.isArray()</code>方法可以确定一个值是否是数组：</p>
<figure class="highlight javascript"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">if</span>(<span class="title class_">Array</span>.<span class="title function_">isArray</span>(value)) {</span><br><span class="line">    <span class="comment">//操作数组</span></span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure>
<h4 id="迭代器方法"><a href="#迭代器方法" class="headerlink" title="迭代器方法"></a>迭代器方法</h4><p>在ES6中，<code>Array</code>的原型上暴露了三个用于检索数组内容的方法：<code>keys()</code>、<code>values()</code>、<code>entries()</code>。</p>
<p><code>keys()</code>返回数组索引的迭代器，<code>values()</code>返回数组元素的迭代器，<code>entries()</code>返回数组索引/值对的迭代器：</p>
<figure class="highlight javascript"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> a = {<span class="string">"foo"</span>,<span class="string">"bar"</span>,<span class="string">"baz"</span>,<span class="string">"qux"</span>};</span><br><span class="line"><span class="comment">// 因为这些方法都返回迭代器，所以可以将它们的内容</span></span><br><span class="line"><span class="comment">// 通过Array.from()方法直接转换为数组实例</span></span><br><span class="line"><span class="keyword">const</span> aKeys = <span class="title class_">Array</span>.<span class="title function_">from</span>(a.<span class="title function_">keys</span>()); <span class="comment">// [0,1,2,3]</span></span><br><span class="line"><span class="keyword">const</span> aValues = <span class="title class_">Array</span>.<span class="title function_">from</span>(a.<span class="title function_">values</span>()); <span class="comment">// ["foo","bar","baz","qux"]</span></span><br><span class="line"><span class="keyword">const</span> aEntries = <span class="title class_">Array</span>.<span class="title function_">from</span>(a.<span class="title function_">entries</span>()); <span class="comment">// [[0,"foo"],[1,"bar"],[2,"baz"],[3,"qux"]]</span></span><br></pre></td></tr></tbody></table></figure>
<p>ES6的结构可以拆分键值对：</p>
<figure class="highlight javascript"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> a = {<span class="string">"foo"</span>,<span class="string">"bar"</span>,<span class="string">"baz"</span>,<span class="string">"qux"</span>};</span><br><span class="line"><span class="keyword">for</span>(<span class="keyword">const</span> [idx,element] <span class="keyword">of</span> a.<span class="title function_">entries</span>()) {</span><br><span class="line">    <span class="title function_">alert</span>(idx);</span><br><span class="line">    <span class="title function_">alert</span>(element);</span><br><span class="line">}</span><br><span class="line"><span class="comment">// 0</span></span><br><span class="line"><span class="comment">//foo</span></span><br><span class="line"><span class="comment">// 1</span></span><br><span class="line"><span class="comment">// bar</span></span><br><span class="line"><span class="comment">// 2</span></span><br><span class="line"><span class="comment">// baz</span></span><br><span class="line"><span class="comment">// 3</span></span><br><span class="line"><span class="comment">// qux</span></span><br></pre></td></tr></tbody></table></figure>
<h4 id="复制和填充方法"><a href="#复制和填充方法" class="headerlink" title="复制和填充方法"></a>复制和填充方法</h4><p>ES6新增了两个方法：批量复制方法<code>copyWithin()</code>和填充数组方法<code>fill()</code>.</p>
<p><code>fill()</code>方法接受三个参数，第一个参数用于指定要填充的元素，第二个参数是开始索引，第三个参数是结束索引，后面两个参数都是可选的。填充的范围是：<font color="#dd0000">[开始索引，结束索引)，也即填充范围包括开始索引不包括结束索引。</font></p>
<ol>
<li>当开始索引和结束索引都缺省时，数组所有元素都填充为给定的值；</li>
<li>当只有开始索引时，数组从开始索引填充到最后一个元素为止；</li>
<li>当开始索引和结束索引都具有时，数组填充指定元素从开始索引到结束索引的前一个元素为止。</li>
</ol>
<p>特殊情况（索引为负值，索引超出边界、反向索引）查阅P144。</p>
<h4 id="join方法"><a href="#join方法" class="headerlink" title="join方法"></a>join方法</h4><p><code>join()</code>方法接受一个参数，即字符分隔符，返回包含所有项的字符串：</p>
<figure class="highlight javascript"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> colors = {<span class="string">"red"</span>,<span class="string">"green"</span>,<span class="string">"blue"</span>};</span><br><span class="line"><span class="title function_">alert</span>(colors.<span class="title function_">join</span>(<span class="string">"-"</span>)); <span class="comment">// red-green-blue</span></span><br></pre></td></tr></tbody></table></figure>
<h4 id="栈方法"><a href="#栈方法" class="headerlink" title="栈方法"></a>栈方法</h4><p><code>ECMAScrip</code>数组提供了<code>push()</code>和<code>pop()</code>方法，用来实现栈的行为。</p>
<ol>
<li><code>push()</code>方法接受任意数量的参数，并将它们添加到数组末尾，返回数组的新长度；</li>
<li><code>pop()</code>方法删除数组最后一项，并返回被删除的项。</li>
</ol>
<font color="#dd0000">栈方法可以与数组的其他方法一起使用。</font>

<h4 id="队列方法"><a href="#队列方法" class="headerlink" title="队列方法"></a>队列方法</h4><p><code>shift()</code>方法删除数组第一项并返回该项，然后让数组长度减一。使用<code>push()</code>和<code>shift()</code>可以把数组当做队列来使用。</p>
<p><code>ECMAScript</code>也为数组提供了<code>unshift()</code>方法，在数组开头添加任意多个值并返回数组新长度。通过使用<code>unshift()</code>和<code>pop()</code>可以在相反的方向上使用队列。</p>
<h4 id="排序方法"><a href="#排序方法" class="headerlink" title="排序方法"></a>排序方法</h4><p><code>reverse()</code>方法用于将数组反向排列。</p>
<p><code>sort()</code>方法在默认情况下会按照升序排列数组元素，但默认的<code>sort()</code>方法把数组每个元素转换成字符串再决定顺序，这显然不适合用于数值或其他类型的数组排序工作。</p>
<p>为了解决这个问题，<code>sort()</code>方法可以接受一个<strong>比较函数</strong>，用于判断哪个值应该在前面。</p>
<p>比较函数接受两个参数，如果第一个参数应该排在第二个参数前面，则返回负值；如果第一个参数应该排在第二个参数后面，则返回正值；如果两个参数相等就返回0。来看下面使用比较函数调用<code>sort()</code>的例子：</p>
<figure class="highlight javascript"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> values = {<span class="number">0</span>,<span class="number">5</span>,<span class="number">1</span>,<span class="number">10</span>,<span class="number">15</span>};</span><br><span class="line"><span class="keyword">function</span> <span class="title function_">compare</span>(<span class="params">value1,value2</span>) {</span><br><span class="line">    <span class="keyword">if</span>(value1 &lt; value2)</span><br><span class="line">        <span class="keyword">return</span> -<span class="number">1</span>;</span><br><span class="line">    <span class="keyword">else</span> <span class="keyword">if</span>(value1 &gt; value2)</span><br><span class="line">        <span class="keyword">return</span> <span class="number">1</span></span><br><span class="line">    <span class="keyword">else</span> <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br><span class="line">values.<span class="title function_">sort</span>(compare);</span><br><span class="line"><span class="title function_">alert</span>(values); <span class="comment">// 0,1,5,10,15</span></span><br></pre></td></tr></tbody></table></figure>
<p>这个比较函数可以进一步简写成箭头函数：</p>
<figure class="highlight javascript"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> values = {<span class="number">0</span>,<span class="number">1</span>,<span class="number">5</span>,<span class="number">10</span>,<span class="number">15</span>};</span><br><span class="line">values.<span class="title function_">sort</span>(<span class="function">(<span class="params">a,b</span>) =&gt;</span> a &lt; b ? -<span class="number">1</span> : a &gt; b ? <span class="number">1</span> : <span class="number">0</span>);</span><br><span class="line">alert (values); <span class="comment">// 0,1,5,10,15</span></span><br></pre></td></tr></tbody></table></figure>
<h4 id="操作方法"><a href="#操作方法" class="headerlink" title="操作方法"></a>操作方法</h4><p>对于数组中元素有很多操作方法。比如<code>concat()</code>方法接收一个参数，首先创建一个数组副本，并将参数全部添加到数组末尾，若接受的参数是数组，则将参数数组中每一项添加到副本数组的末尾。</p>
<h4 id="迭代方法"><a href="#迭代方法" class="headerlink" title="迭代方法"></a>迭代方法</h4><p><code>ECMAScript</code>为数组定义了5个迭代方法，每个迭代方法接受两个参数：对数组每一项运行的函数，可选的作为函数运行上下文的作用域对象。传给每个方法的函数接受三个参数：数组元素、元素索引和数组本身。</p>
<p>下面是五个迭代方法的介绍：</p>
<ol>
<li><code>every()</code>：对数组每一项都运行传入的函数，如果每一项函数都返回<code>true</code>，则这个方法返回<code>true</code>；</li>
<li><code>some()</code>：对数组的每一项都运行传入的函数，只要有一项函数返回<code>true</code>，则这个方法返回<code>true</code>；</li>
<li><code>filter()</code>：对数组的每一项都运行传入的函数，函数返回<code>true</code>的项组成数组后返回；</li>
<li><code>map()</code>：对数组的每一项都运行传入的函数，返回每一项函数调用的结果构成的数组；</li>
<li><code>forEach()</code>：对数组的每一项都运行传入的函数，没有返回值。</li>
</ol>
<p><font color="#dd0000">这些方法都不改变原数组。</font>看下面的例子：</p>
<figure class="highlight javascript"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> numbers = {<span class="number">1</span>,<span class="number">2</span>,<span class="number">3</span>,<span class="number">4</span>,<span class="number">5</span>,<span class="number">4</span>,<span class="number">3</span>,<span class="number">2</span>,<span class="number">1</span>};</span><br><span class="line"><span class="keyword">let</span> everyResult = numbers.<span class="title function_">every</span>(<span class="function">(<span class="params">item,index,array</span>) =&gt;</span> item &gt; <span class="number">2</span>);</span><br><span class="line"><span class="title function_">alert</span>(everyResult); <span class="comment">// false</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> someResult = numbers.<span class="title function_">some</span>(<span class="function">(<span class="params">item,index,array</span>) =&gt;</span> item &gt; <span class="number">2</span>);</span><br><span class="line"><span class="title function_">alert</span>(someResult); <span class="comment">//true</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> filterResult = numbers.<span class="title function_">filter</span>(<span class="function">(<span class="params">item,index,array</span>) =&gt;</span> item &gt; <span class="number">2</span>);</span><br><span class="line"><span class="title function_">alert</span>(filterResult); <span class="comment">// [3,4,5,4,3]</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> mapResult = numbers.<span class="title function_">map</span>(<span class="function">(<span class="params">item,index,array</span>) =&gt;</span> item * <span class="number">2</span>);</span><br><span class="line"><span class="title function_">alert</span>(mapResult); <span class="comment">// [2,4,6,8,10,8,6,4,2]</span></span><br><span class="line"></span><br><span class="line">numbers.<span class="title function_">forEach</span>(<span class="function">(<span class="params">item,index,array</span>) =&gt;</span> item *<span class="number">2</span>);</span><br><span class="line"><span class="title function_">alert</span>(numbers); <span class="comment">// [2,4,6,8,10,8,6,4,2]</span></span><br></pre></td></tr></tbody></table></figure>
<h3 id="6-3-page-with-curl-定型数组"><a href="#6-3-page-with-curl-定型数组" class="headerlink" title="6.3 :page_with_curl:定型数组"></a>6.3 <span class="github-emoji"><span>📃</span><img src="https://github.githubassets.com/images/icons/emoji/unicode/1f4c3.png?v8" aria-hidden="true" onerror="this.parent.classList.add('github-emoji-fallback')"></span>定型数组</h3><p>待学习</p>
<h3 id="6-4-page-with-curl-Map"><a href="#6-4-page-with-curl-Map" class="headerlink" title="6.4 :page_with_curl:Map"></a>6.4 <span class="github-emoji"><span>📃</span><img src="https://github.githubassets.com/images/icons/emoji/unicode/1f4c3.png?v8" aria-hidden="true" onerror="this.parent.classList.add('github-emoji-fallback')"></span>Map</h3><p><code>Map</code>是ES6中新增的一种集合类型，为JS带来了真正的键/值存储机制。</p>
<h4 id="基本API"><a href="#基本API" class="headerlink" title="基本API"></a>基本API</h4><p>使用<code>new</code>关键字和<code>Map</code>构造器创建一个空映射:</p>
<figure class="highlight javascript"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> m = <span class="keyword">new</span> <span class="title class_">Map</span>();</span><br></pre></td></tr></tbody></table></figure>
<p>可以在创建的同时初始化实例，给<code>Map</code>构造函数传入一个可迭代对象，需要包含键值对数组，可迭代对象中的每个键值对都会按照迭代顺序插入到新映射实例中：</p>
<figure class="highlight javascript"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> m1 = <span class="keyword">new</span> <span class="title class_">Map</span>([</span><br><span class="line">    [<span class="string">"key1"</span>,<span class="string">"val1"</span>],</span><br><span class="line">    [<span class="string">"key2"</span>.<span class="string">"val2"</span>]</span><br><span class="line">]);</span><br><span class="line"><span class="title function_">alert</span>(m1.<span class="property">size</span>); <span class="comment">// 2</span></span><br></pre></td></tr></tbody></table></figure>
<p>初始化之后可以使用<code>set()</code>方法添加键值对，使用<code>get()</code>和<code>has()</code>方法获取键值、检测某个键值对是否存在，还可以使用<code>delete()</code>和<code>clear()</code>删除值,最后可以使用<code>size()</code>方法获取键值对数量：</p>
<figure class="highlight javascript"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> m = <span class="keyword">new</span> <span class="title class_">Map</span>();</span><br><span class="line"><span class="title function_">alert</span>(m.<span class="title function_">has</span>(<span class="string">"firstName"</span>)); <span class="comment">// false</span></span><br><span class="line"><span class="title function_">alert</span>(m.<span class="title function_">get</span>(<span class="string">"firstName"</span>)); <span class="comment">// undefined</span></span><br><span class="line"><span class="title function_">alert</span>(m.<span class="property">size</span>); <span class="comment">// 0</span></span><br><span class="line"></span><br><span class="line">m.<span class="title function_">set</span>(<span class="string">"firstName"</span>,<span class="string">"Matt"</span>)</span><br><span class="line"> .<span class="title function_">set</span>(<span class="string">"lastName"</span>,<span class="string">"Frisbie"</span>);</span><br><span class="line"><span class="title function_">alert</span>(m.<span class="title function_">has</span>(<span class="string">"firstName"</span>)); <span class="comment">// true</span></span><br><span class="line"><span class="title function_">alert</span>(m.<span class="title function_">get</span>(<span class="string">"firstName"</span>)); <span class="comment">// Matt</span></span><br><span class="line"><span class="title function_">alert</span>(m.<span class="property">size</span>); <span class="comment">// 2</span></span><br><span class="line"></span><br><span class="line">m.<span class="title function_">delete</span>(<span class="string">"firstName"</span>); <span class="comment">//删除这一个键值对</span></span><br><span class="line"><span class="title function_">alert</span>(m.<span class="title function_">has</span>(<span class="string">"firstName"</span>)); <span class="comment">// false</span></span><br><span class="line"><span class="title function_">alert</span>(m.<span class="title function_">get</span>(<span class="string">"firstName"</span>)); <span class="comment">// undefined</span></span><br><span class="line"></span><br><span class="line">m.<span class="title function_">clear</span>() <span class="comment">// 删除所有键值对</span></span><br><span class="line"><span class="title function_">alert</span>(m.<span class="property">size</span>); <span class="comment">// 0</span></span><br></pre></td></tr></tbody></table></figure>
<p><code>Map</code>可以使用任何JavaScript数据类型为键，</p>
<h2 id="第八章-对象、类与面向对象变成"><a href="#第八章-对象、类与面向对象变成" class="headerlink" title="第八章 对象、类与面向对象变成"></a>第八章 对象、类与面向对象变成</h2><h3 id="8-1-使用对象字面量创建对象实例"><a href="#8-1-使用对象字面量创建对象实例" class="headerlink" title="8.1 使用对象字面量创建对象实例"></a>8.1 使用对象字面量创建对象实例</h3><figure class="highlight javascript"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> person = {</span><br><span class="line">    <span class="attr">name</span>: <span class="string">"吴大孬"</span>,</span><br><span class="line">    <span class="attr">age</span>: <span class="number">18</span>,</span><br><span class="line">    <span class="attr">job</span>: {</span><br><span class="line">        <span class="attr">jpbName</span>: <span class="string">"牙医"</span>,</span><br><span class="line">        <span class="attr">salary</span>: <span class="number">20000</span></span><br><span class="line">    }</span><br><span class="line">    <span class="title function_">sayLove</span>(<span class="params"></span>) {</span><br><span class="line">        <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">"我爱詹向飞！"</span>);</span><br><span class="line">    }</span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure>
<h3 id="8-2-属性的类型"><a href="#8-2-属性的类型" class="headerlink" title="8.2 属性的类型"></a>8.2 属性的类型</h3><p><code>ECMAScript</code>把对象属性分两种：<strong>数据属性</strong>和<strong>访问器属性</strong>。并且使用一些内部特征用来描述属性。</p>
<h4 id="数据属性"><a href="#数据属性" class="headerlink" title="数据属性"></a>数据属性</h4><p>JavaScript中对象的数据属性的值保存在属性的一个特征属性中，数据属性一共有以下四个特征属性：</p>
<ol>
<li><code>[[Configurable]]</code>：表示属性是否可以通过<code>delete</code>删除并重新定义，是否可以修改它的特性</li>
</ol>
<h2 id="bookmark-tabs-零散知识点"><a href="#bookmark-tabs-零散知识点" class="headerlink" title=":bookmark_tabs:零散知识点"></a><span class="github-emoji"><span>📑</span><img src="https://github.githubassets.com/images/icons/emoji/unicode/1f4d1.png?v8" aria-hidden="true" onerror="this.parent.classList.add('github-emoji-fallback')"></span>零散知识点</h2><h3 id="解构"><a href="#解构" class="headerlink" title="解构"></a>解构</h3>
      
    </div>

    
    
    

    <footer class="post-footer">
        <div class="post-eof"></div>
      
    </footer>
  </article>
</div>




    


<div class="post-block">
  
  

  <article itemscope itemtype="http://schema.org/Article" class="post-content" lang="">
    <link itemprop="mainEntityOfPage" href="http://xiaoqingming18.github.io/2023/04/05/JAVA%E6%A0%B8%E5%BF%83%E6%8A%80%E6%9C%AF%E5%8D%B7I-%E8%AF%BB%E4%B9%A6%E7%AC%94%E8%AE%B0/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="image" content="/images/avatar.gif">
      <meta itemprop="name" content="鸣蜩十七">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="鸣蜩十七">
      <meta itemprop="description" content="记录我的学习、生活和恋爱日常">
    </span>

    <span hidden itemprop="post" itemscope itemtype="http://schema.org/CreativeWork">
      <meta itemprop="name" content="undefined | 鸣蜩十七">
      <meta itemprop="description" content="">
    </span>
      <header class="post-header">
        <h2 class="post-title" itemprop="name headline">
          <a href="/2023/04/05/JAVA%E6%A0%B8%E5%BF%83%E6%8A%80%E6%9C%AF%E5%8D%B7I-%E8%AF%BB%E4%B9%A6%E7%AC%94%E8%AE%B0/" class="post-title-link" itemprop="url">JAVA核心技术卷I-读书笔记</a>
        </h2>

        <div class="post-meta-container">
          <div class="post-meta">
    <span class="post-meta-item">
      <span class="post-meta-item-icon">
        <i class="far fa-calendar"></i>
      </span>
      <span class="post-meta-item-text">发表于</span>

      <time title="创建时间：2023-04-05 21:35:43" itemprop="dateCreated datePublished" datetime="2023-04-05T21:35:43+08:00">2023-04-05</time>
    </span>
    <span class="post-meta-item">
      <span class="post-meta-item-icon">
        <i class="far fa-calendar-check"></i>
      </span>
      <span class="post-meta-item-text">更新于</span>
      <time title="修改时间：2023-04-18 09:37:36" itemprop="dateModified" datetime="2023-04-18T09:37:36+08:00">2023-04-18</time>
    </span>

  
</div>

        </div>
      </header>

    
    
    
    <div class="post-body" itemprop="articleBody">
          <h1 id="JAVA核心技术卷I-读书笔记"><a href="#JAVA核心技术卷I-读书笔记" class="headerlink" title="JAVA核心技术卷I 读书笔记"></a>JAVA核心技术卷I 读书笔记</h1><h2 id="bookmark-tabs-第六章-接口、表达式与内部类"><a href="#bookmark-tabs-第六章-接口、表达式与内部类" class="headerlink" title=":bookmark_tabs:第六章 接口、表达式与内部类"></a><span class="github-emoji"><span>📑</span><img src="https://github.githubassets.com/images/icons/emoji/unicode/1f4d1.png?v8" aria-hidden="true" onerror="this.parent.classList.add('github-emoji-fallback')"></span>第六章 接口、表达式与内部类</h2><p>[<span class="github-emoji"><span>✒</span><img src="https://github.githubassets.com/images/icons/emoji/unicode/2712.png?v8" aria-hidden="true" onerror="this.parent.classList.add('github-emoji-fallback')"></span>章节内容简介] 本章首先介绍<code>接口</code>，接口用来描述类应该做什么，而不指定应该如何做，一个类可以实现一个或多个接口，这是接口与抽象类最大的不同。再继续介绍<code>lambda表达式</code>，这是一种很简洁的用来创建将来要执行的代码块的方法，通过使用lambda表达式，可以以一种很方便、简洁的方式使用<code>回调</code>或可变行为的代码。<code>内部类</code>是定义在另一个类中的内部的类。</p>
<h3 id="page-with-curl-6-1-接口"><a href="#page-with-curl-6-1-接口" class="headerlink" title=":page_with_curl:6.1 接口"></a><span class="github-emoji"><span>📃</span><img src="https://github.githubassets.com/images/icons/emoji/unicode/1f4c3.png?v8" aria-hidden="true" onerror="this.parent.classList.add('github-emoji-fallback')"></span>6.1 接口</h3><h4 id="接口的概念"><a href="#接口的概念" class="headerlink" title="接口的概念"></a>接口的概念</h4><p>接口不是类，而是对希望符合这个接口的类的一组需求，这和抽象类很相似，也就是接口是用来表达一个类的需求的，不需要具体实现，具体实现由实现这个接口的类来完成。</p>
<p>下面给出一个示例，Array类中的<code>sort</code>方法可以对对象数组进行排序，但是要排序的对象数组中的对象必须实现<code>Comparable</code>接口，下面是Comparable接口的代码：</p>
<figure class="highlight java"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">interface</span> <span class="title class_">Comparable</span> {</span><br><span class="line">    <span class="type">int</span> <span class="title function_">compareTo</span><span class="params">(Object other)</span>;</span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure>
<p>由此可见，任何实现<code>Comparable</code>接口的类都需要包含<code>compareTo</code>方法，在接口中只指出实现这个接口的类需要实现这个方法，也就是接口中的是抽象方法，这个方法的具体实现交给实现这个接口的类来完成。</p>
<p>接口中所有方法都自动是<code>public</code>方法，所以在接口中声明方法时，不必提供关键字<code>public</code>。</p>
<p>除此以外，<font color="#dd0000">接口绝不会有实例字段，但是可以包含常量</font>并且<strong>在JAVA8之前</strong>，<font color="#dd0000">接口中也绝不会实现方法</font>（现在已经可以在接口中提供其他方法了，后面会说到）。但是其他方法不能引用实例字段，因为<font color="#dd0000">接口没有实例字段。</font></p>
<p>如上所述，可以将接口看成是<font color="#dd0000">没有实例字段的抽象类。</font></p>
<h4 id="让类实现接口"><a href="#让类实现接口" class="headerlink" title="让类实现接口"></a>让类实现接口</h4><p>要让类实现某个接口需要完成下面两个步骤：</p>
<ol>
<li>将类声明为实现给定的接口。</li>
<li>对接口中的<strong>所有方法</strong>提供定义。</li>
</ol>
<p>将类声明为实现给定的接口，需要使用关键字<code>implements</code>：</p>
<figure class="highlight java"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Employee</span> <span class="keyword">implements</span> <span class="title class_">Comparable</span></span><br></pre></td></tr></tbody></table></figure>
<p>下一步就是实现接口中的<strong>所有</strong>抽象方法，<code>Comparable</code>接口中只有一个用于比较的<code>compareTo</code>方法：</p>
<figure class="highlight java"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Employee</span> <span class="keyword">implements</span> <span class="title class_">Comparable</span> {</span><br><span class="line">    <span class="keyword">public</span> <span class="type">int</span> <span class="title function_">compareTo</span><span class="params">(Object otherObject)</span> {</span><br><span class="line">        <span class="type">Employee</span> <span class="variable">other</span> <span class="operator">=</span> (Employee) otherObject;</span><br><span class="line">        <span class="keyword">return</span> Double.compare(salary,other.salary);</span><br><span class="line">    }</span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure>
<p>在上面的代码中，我们使用了静态<code>Double.compare</code>方法。如果第一个参数小于第二个参数，它会返回一个负值，相等则返回0，否则返回正值。</p>
<p>这样我们的<code>Employee</code>对象数组就可以通过调用<code>Array.sort</code>方法进行排序了，上面的代码是通过薪水排序。</p>
<p>这里可以做的更好一些，为泛型<code>Comparable</code>接口提供一个类型参数：</p>
<figure class="highlight java"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Employee</span> <span class="keyword">implements</span> <span class="title class_">Comparable</span>&lt;Employee&gt; {</span><br><span class="line">    <span class="keyword">public</span> <span class="type">int</span> <span class="title function_">compareTo</span><span class="params">(Employee other)</span> {</span><br><span class="line">        <span class="keyword">return</span> Double.compare(salary,other.salary);</span><br><span class="line">    }</span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure>
<p>这样一来就不用对<code>Object</code>参数进行类型转换了。这里用到了<strong>泛型</strong>，后面会详细叙述。</p>
<h5 id="本节提到的功能函数："><a href="#本节提到的功能函数：" class="headerlink" title="本节提到的功能函数："></a>本节提到的功能函数：</h5><div class="table-container">
<table>
<thead>
<tr>
<th>API</th>
<th>原型</th>
<th>功能</th>
</tr>
</thead>
<tbody>
<tr>
<td>java.lang.Comparable<t></t></td>
<td>int compareTo(T other)</td>
<td>用这个对象与other进行比较。如果这个对象小于other<br>就返回一个负整数；如果相等就返回0；否则返回一个正整数。</td>
</tr>
<tr>
<td>java.util.Arrays</td>
<td>static void sort(Object[] a)</td>
<td>对数组a中的元素进行排序。要求数组中的元素必须属于实现了<br><code>Comparable</code>接口的类，并且元素之间是可比较的。</td>
</tr>
<tr>
<td>java.lang.Integer</td>
<td>static int compare(int x,int y)</td>
<td>如果x&lt;y返回一个负整数；相等返回0；否则返回一个正整数。</td>
</tr>
<tr>
<td>java.lang.Double</td>
<td>static int compare(double x,double y)</td>
<td>如果x&lt;y返回一个负整数；相等返回0；否则返回一个正整数。</td>
</tr>
</tbody>
</table>
</div>
<h4 id="接口的属性"><a href="#接口的属性" class="headerlink" title="接口的属性"></a>接口的属性</h4><p>接口不是类，<font color="#dd0000">不能使用<code>new</code>操作符实例化一个接口，</font>但可以声明接口的变量，并且接口的变量<strong>必须</strong>引用实现了这个接口的类的对象：</p>
<figure class="highlight java"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">Comparable</span> <span class="variable">x</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">Employee</span>();</span><br></pre></td></tr></tbody></table></figure>
<p>也可以使用<code>instanceof</code>检查一个对象是否实现了某个特定的接口：</p>
<figure class="highlight java"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">if</span>(anObject <span class="keyword">instanceof</span> Comparable) {···};</span><br></pre></td></tr></tbody></table></figure>
<p>与类的继承一样，接口也可以<strong>扩展</strong>，假设有一个<code>Moveable</code>的接口：</p>
<figure class="highlight java"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">interface</span> <span class="title class_">Moveable</span> {</span><br><span class="line">    <span class="keyword">void</span> <span class="title function_">move</span><span class="params">(<span class="type">double</span> x,<span class="type">double</span> y)</span> {···};</span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure>
<p>然后可以假设一个<code>Powered</code>接口扩展<code>Moveable</code>接口：</p>
<figure class="highlight java"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">interface</span> <span class="title class_">Powered</span> <span class="keyword">extends</span> <span class="title class_">Moveable</span> {</span><br><span class="line">    <span class="type">double</span> milesPerGallon;</span><br><span class="line">    <span class="type">double</span> <span class="variable">SPEED_LIMIT</span> <span class="operator">=</span> <span class="number">95</span>；</span><br><span class="line">} </span><br></pre></td></tr></tbody></table></figure>
<p>哲理又复习了一下，<font color="#dd0000">接口不能有实例字段但是可以有常量。</font>接口中的字段总是<code>public static final</code>，可以省略。</p>
<p>与抽象类不同，一个类可以实现多个接口，只需要用逗号分割不同的接口名：</p>
<figure class="highlight java"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Employee</span> <span class="keyword">implements</span> <span class="title class_">Cloneable</span>,Comparable {···};</span><br></pre></td></tr></tbody></table></figure>
<h4 id="静态和私有方法"><a href="#静态和私有方法" class="headerlink" title="静态和私有方法"></a>静态和私有方法</h4><p>在Java8中，允许在接口中增加静态方法。</p>
<p>在Java9中，接口中的方法可以是<code>private</code>。由于<font color="#dd0000">私有方法只能在接口本身的方法中使用，</font>所以只能作为接口中其他方法的辅助方法。</p>
<h4 id="默认方法"><a href="#默认方法" class="headerlink" title="默认方法"></a>默认方法</h4><p>可以为接口提供<strong>默认方法</strong>，用<code>default</code>修饰符修饰：</p>
<figure class="highlight java"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">interface</span> <span class="title class_">Comparablle</span>&lt;T&gt; {</span><br><span class="line">    <span class="keyword">default</span> <span class="type">int</span> <span class="title function_">compareTo</span><span class="params">(T other)</span> {<span class="keyword">return</span> <span class="number">0</span>;}</span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure>
<p>需要注意的是，<code>Comparable</code>的每一个具体实现都会覆盖这个默认方法。</p>
<p>默认方法的一个重要用法是<strong>接口演化</strong>。假设很久以前你提供了这样一个类：</p>
<figure class="highlight java"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Bag</span> <span class="keyword">implements</span> <span class="title class_">Collection</span></span><br></pre></td></tr></tbody></table></figure>
<p>后来又为这个接口增加了一个<code>stream</code>方法。假设<code>stream</code>不是一个默认方法，那么<code>Bag</code>类将不能编译，因为它没有实现这个新方法。<font color="#dd0000">为接口增加一个非默认方法无法保证“源代码兼容”</font>。将新方法设置为默认方法就可以轻松解决这个问题。</p>
<h4 id="解决默认方法冲突"><a href="#解决默认方法冲突" class="headerlink" title="解决默认方法冲突"></a>解决默认方法冲突</h4><p>如果现在一个接口中定义了一个默认方法，然后又在超类或另一个接口中定义同名方法，Java处理的规则如下：</p>
<ol>
<li>超类优先。如果超类提供了一个具体方法，同名而且有相同参数类型的默认方法会被忽略。如果一个类扩展了一个超类同时实现了一个接口，并同时从超类和接口中继承了相同的方法，<font color="#dd0000">只会考虑超类方法，接口中默认方法被忽略。</font></li>
<li>接口冲突。如果一个接口提供了一个默认方法，另一个接口提供了一个同名而且具有相同参数类型的方法，必须覆盖这个方法来解决冲突。</li>
</ol>
<p>下面举例说明第二条接口冲突的规则：</p>
<p>假设有两个包含<code>getName</code>方法的接口：</p>
<figure class="highlight java"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">interface</span> <span class="title class_">Person</span> {</span><br><span class="line">    <span class="keyword">default</span> <span class="title function_">getName</span><span class="params">()</span> {<span class="keyword">return</span> <span class="string">""</span>;}</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">interface</span> <span class="title class_">Named</span> {</span><br><span class="line">    <span class="keyword">default</span> <span class="title function_">getName</span><span class="params">()</span> {<span class="keyword">return</span> getClass().getName() + <span class="string">"_"</span> + hashCode();}</span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure>
<p>如果有一个类同时实现了这两个接口，就需要选择两个冲突方法中的一个：</p>
<figure class="highlight java"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Student</span> <span class="keyword">implements</span> <span class="title class_">Person</span>,Named {</span><br><span class="line">    <span class="keyword">public</span> String <span class="title function_">getName</span><span class="params">()</span> {<span class="keyword">return</span> Person.<span class="built_in">super</span>.Name();}</span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure>
<h4 id="接口与回调"><a href="#接口与回调" class="headerlink" title="接口与回调"></a>接口与回调</h4><p>这部分内容用一段代码来理解：</p>
<figure class="highlight java"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">TimerTest</span> {</span><br><span class="line">    <span class="type">var</span> <span class="variable">listener</span> <span class="operator">=</span> nre <span class="title function_">TimePrinter</span><span class="params">()</span>;</span><br><span class="line">    <span class="type">var</span> <span class="variable">timer</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">Timer</span>(<span class="number">1000</span>,listener);</span><br><span class="line">    timer.start();</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">TimePrinter</span> <span class="keyword">implements</span> <span class="title class_">ActionListener</span> {</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">actionPerformed</span><span class="params">(ActionEvent event)</span> {</span><br><span class="line">        System.out.println(<span class="string">"At the tone,the time is "</span></span><br><span class="line">                          + Instant.ofEpochMilli(event.getWhen()));</span><br><span class="line">        Toolkit.getDefaultToolkit().beep();</span><br><span class="line">    }</span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure>
<h4 id="Comparator接口"><a href="#Comparator接口" class="headerlink" title="Comparator接口"></a>Comparator接口</h4><p>在前面我们已经了解了，实现了<code>Comparable</code>接口的对象数组可以进行排序。例如我们可以对一个字符数组进行排序，因为<code>String</code>类实现了<code>Comparable&lt;T&gt;</code>，而且<code>String.compareTo</code>方法可以按字典顺序比较字符串。</p>
<p>现在我们希望按长度递增的顺序对字符串排序，而不是按字典顺序进行排序。为此，我们可以使用<font color="#dd0000"><code>Array.sort</code>的第二个版本，</font>有一个数组和一个<strong>比较器</strong>作为参数，比较器是实现了<code>Comparator</code>接口的类的实例：</p>
<figure class="highlight java"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">interface</span> <span class="title class_">Comparator</span>&lt;t&gt; {</span><br><span class="line">    <span class="type">int</span> <span class="title function_">compare</span><span class="params">(T first,T second)</span>;</span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure>
<p>要按长度比较字符串，可以如下定义一个实现<code>Comparator&lt;String&gt;</code>的类：</p>
<figure class="highlight java"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">LengthComparator</span> <span class="keyword">implements</span> <span class="title class_">Comparator</span>&lt;String&gt; {</span><br><span class="line">    <span class="keyword">public</span> <span class="type">int</span> <span class="title function_">compare</span><span class="params">(String first,String second)</span> {</span><br><span class="line">        <span class="keyword">return</span> first.length() - second.length;</span><br><span class="line">    }</span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure>
<p>具体完成比较时，需要建立一个实例：</p>
<figure class="highlight java"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">var</span> <span class="variable">comp</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">LengthComparator</span>();</span><br></pre></td></tr></tbody></table></figure>
<p>要对一个数组排序，需要为<code>Array.sort</code>方法传入一个<code>LengthComparator</code>对象：</p>
<figure class="highlight java"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">String[] friends = {<span class="string">"Peter"</span>,<span class="string">"Paul"</span>,<span class="string">"Mary"</span>};</span><br><span class="line">Array.sort(friends,<span class="keyword">new</span> <span class="title class_">LengthComparator</span>());</span><br></pre></td></tr></tbody></table></figure>
<h4 id="对象克隆"><a href="#对象克隆" class="headerlink" title="对象克隆"></a>对象克隆</h4><p><code>Cloneable</code>接口提供了一个安全的<code>clone</code>方法：</p>
<figure class="highlight java"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">var</span> <span class="variable">original</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">Employee</span>(<span class="string">"John Public"</span>,<span class="number">50000</span>);</span><br><span class="line"><span class="type">Employee</span> <span class="variable">copy</span> <span class="operator">=</span> original.clone();</span><br><span class="line">copy.raiseSalary(<span class="number">10</span>); <span class="comment">//original不会改变</span></span><br></pre></td></tr></tbody></table></figure>
<p>但是这样的拷贝只是<strong>浅拷贝</strong>，如果对象中包含子对象的引用，拷贝字段就会得到相同子对象的另一个引用，这样一来，原对象和克隆对象仍然会共享一些信息。想要避免这种情况，就需要进行<strong>深拷贝</strong>，<font color="#dd0000">深拷贝需要通过重写<code>clone</code>方法来进行。</font></p>
<p>需要注意的是，虽然<code>clone</code>方法是直接从<code>Object</code>类继承来的，但<font color="#dd0000">如果一个对象请求克隆，但是没有显式地实现<code>cloneable</code>接口，就会生成一个检查型异常。</font>除此之外，还需要在重写<code>clone</code>方法时将其定义为<code>public</code>。</p>
<p>综上所述，即使<code>clone</code>的默认浅拷贝实现能够满足需求，还是要实现<code>Cloneable</code>接口，将<code>clone</code>重新定义为<code>public</code>，再调用<code>super.clone()</code>。</p>
<p>下面来看创建浅拷贝的<code>clone</code>方法的一个例子：</p>
<figure class="highlight java"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Employee</span> <span class="keyword">implements</span> <span class="title class_">Cloneable</span> {</span><br><span class="line">    <span class="keyword">public</span> Employee <span class="title function_">clone</span><span class="params">()</span> <span class="keyword">throws</span> CloneNotSupportedException {</span><br><span class="line">        <span class="keyword">return</span> (Employee) <span class="built_in">super</span>.clone;</span><br><span class="line">    }</span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure>
<p>下面来看创建深拷贝的<code>clone</code>方法的一个例子：</p>
<figure class="highlight java"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Employee</span> <span class="keyword">implements</span> <span class="title class_">Cloneable</span> {</span><br><span class="line">    <span class="keyword">public</span> Employee <span class="title function_">clone</span><span class="params">()</span> <span class="keyword">throws</span> CloneNotSupportedExpection {</span><br><span class="line">        <span class="type">Employee</span> <span class="variable">cloned</span> <span class="operator">=</span> (Employee) <span class="built_in">super</span>.clone();</span><br><span class="line">        <span class="comment">//下面对Employee子对象进行拷贝</span></span><br><span class="line">        cloned.hireDay = (Date) hireDay.clone();</span><br><span class="line">        <span class="keyword">return</span> cloned;</span><br><span class="line">    }</span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure>
<p>我们来总结一下，对于每一个类，需要确定：</p>
<ol>
<li>默认的<code>clone</code>方法能否满足需求？</li>
<li>是否可以在可变子对象上调用<code>clone</code>方法来修补默认的<code>clone</code>方法；</li>
<li>是否不该使用<code>clone</code>？</li>
</ol>
<p>实际上第3个是默认选项，如果选择第1或第2选项，类必须：</p>
<ol>
<li>实现<code>Cloneable</code>接口；</li>
<li>重新定义<code>clone</code>方法，并指定<code>public</code>访问修饰符。</li>
</ol>
<h3 id="page-with-curl-6-2-lambda表达式"><a href="#page-with-curl-6-2-lambda表达式" class="headerlink" title=":page_with_curl:6.2 lambda表达式"></a><span class="github-emoji"><span>📃</span><img src="https://github.githubassets.com/images/icons/emoji/unicode/1f4c3.png?v8" aria-hidden="true" onerror="this.parent.classList.add('github-emoji-fallback')"></span>6.2 lambda表达式</h3><p>lambda表达式是一个可传递的代码块，可以在以后执行一次或多次，下面我们来看看哪些地方可以用到lambda表达式。</p>
<p>继续看之前说到的排序例子，我们传入代码来检查一个字符串是否比另一个字符串短，现在我们可以用lambda表达式这样写：</p>
<figure class="highlight java"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">(String first,String second)</span><br><span class="line">-&gt; first.length() - second.length();</span><br></pre></td></tr></tbody></table></figure>
<p>如果代码要完成的计算无法在一个表达式中完成，还可以把这些代码放在<code>{}</code>块中，并包含<code>return</code>语句，像下面这样：</p>
<figure class="highlight java"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">(String first,String second) -&gt; {</span><br><span class="line">    <span class="keyword">if</span>(first.length() &lt; second.length()) <span class="keyword">return</span> -<span class="number">1</span>;</span><br><span class="line">    <span class="keyword">else</span> <span class="keyword">if</span>(first.length() &gt; second.length()) <span class="keyword">return</span> <span class="number">1</span>;</span><br><span class="line">    <span class="keyword">else</span> <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure>
<p>如果lambda表达式没有参数，也要提供一对空括号：</p>
<figure class="highlight java"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">() -&gt; {<span class="keyword">for</span>(<span class="type">int</span> <span class="variable">i</span> <span class="operator">=</span> <span class="number">100</span>;i &gt;= <span class="number">0</span>;i--)System.out.println(i);}</span><br></pre></td></tr></tbody></table></figure>
<p>如果可以推导出lambda表达式的参数类型，则可以忽略其类型.</p>
<h4 id="函数式接口"><a href="#函数式接口" class="headerlink" title="函数式接口"></a>函数式接口</h4><p>对于只有一个抽象方法的接口，需要这种接口的对象时，就可以提供一个lambda表达式，这种接口成为<strong>函数式接口</strong>。</p>
<p>为了展示如何转换为函数式接口，下面考虑<code>Arrays.sort</code>方法。它的第二个参数需要一个<code>Comparator</code>示例，<code>Comparator</code>就是只有一个方法的接口，所以可以提供一个lambda表达式：</p>
<figure class="highlight java"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">Arrays.sort(words,</span><br><span class="line">           (first,second) -&gt; first.length() - second.length());</span><br></pre></td></tr></tbody></table></figure>
<h3 id="page-with-curl-6-3-内部类"><a href="#page-with-curl-6-3-内部类" class="headerlink" title=":page_with_curl:6.3 内部类"></a><span class="github-emoji"><span>📃</span><img src="https://github.githubassets.com/images/icons/emoji/unicode/1f4c3.png?v8" aria-hidden="true" onerror="this.parent.classList.add('github-emoji-fallback')"></span>6.3 内部类</h3><p><strong>内部类</strong>是定义在另一个类中的类，内部类有以下特点：</p>
<ol>
<li>内部类可以对同一个包中的其他类隐藏</li>
<li>内部类方法可以访问定义这个类的作用域中的数据，包括私有数据（<font color="#dd0000">也即内部类可以访问外类数据，包括外部类的私有数据</font>）</li>
</ol>
<p>通过下面的例子简单了解一下内部类的使用：</p>
<figure class="highlight java"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">TalkingClock</span> {</span><br><span class="line">    <span class="keyword">private</span> <span class="type">int</span> interval;</span><br><span class="line">    <span class="keyword">private</span> <span class="type">boolean</span> beep;</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">public</span> <span class="title function_">TalkingClock</span><span class="params">(<span class="type">int</span> interval,<span class="type">boolean</span> beep)</span> {</span><br><span class="line">        <span class="built_in">this</span>.interval = interval;</span><br><span class="line">        <span class="built_in">this</span>.beep = beep;</span><br><span class="line">    }</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">start</span><span class="params">()</span> {</span><br><span class="line">        <span class="type">var</span> <span class="variable">listener</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">TimePrinter</span>();</span><br><span class="line">        <span class="type">var</span> <span class="variable">timer</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">Timer</span>(interval,listener);</span><br><span class="line">        time.start();</span><br><span class="line">    }</span><br><span class="line">    <span class="comment">//下面是内部类的定义</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">TimePrinter</span> <span class="keyword">implements</span> <span class="title class_">ActionListener</span> {</span><br><span class="line">        <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">actionPerformed</span><span class="params">(AcitonEvent event)</span> {</span><br><span class="line">            System.out.println(<span class="string">"At the tone,the time is "</span></span><br><span class="line">                              + Instant.ofEpochMilli(event.getWhen()));</span><br><span class="line">            <span class="keyword">if</span>(beep) Toolkit.getDefaultToolkit().beep();</span><br><span class="line">        }</span><br><span class="line">    }</span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure>
<p>上面的代码中，<code>TimePrinter</code>类中并没有<code>beep</code>字段，但是确仍旧可以访问该字段，这说明，<font color="#dd0000">一个内部类方法可以访问外部类的数据字段，包括私有字段。</font>为此，内部类的对象总有一个隐式引用，指向创建它的外部类对象，这个引用在内部类的定义中是不可见的。</p>
<h4 id="内部类的特殊语法规则"><a href="#内部类的特殊语法规则" class="headerlink" title="内部类的特殊语法规则"></a>内部类的特殊语法规则</h4><p>表达式<code>OuterClass.this</code>表示外部类的引用。例如，可以像下面这样编写<code>TimePrinter</code>类中的<code>actionPerformed</code>方法：</p>
<figure class="highlight java"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">actionPerformed</span><span class="params">(ActionEvent event)</span> {</span><br><span class="line">    ···</span><br><span class="line">    <span class="keyword">if</span>(TalkingClock.<span class="built_in">this</span>.beep) Toolkit.getDefaultTolkit.beep();</span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure>
<p>反过来，可以采用以下语法更加明确地编写内部类对象的构造器：</p>
<figure class="highlight java"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">outerObject.<span class="keyword">new</span> <span class="title class_">InnerClass</span>(construction parameters)</span><br></pre></td></tr></tbody></table></figure>
<p>例如：</p>
<figure class="highlight java"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">ActionListener</span> <span class="variable">listener</span> <span class="operator">=</span> <span class="built_in">this</span>.<span class="keyword">new</span> <span class="title class_">TimePrinter</span>();</span><br></pre></td></tr></tbody></table></figure>
<p>在外围类的作用域之外，可以这样引用内部类：</p>
<figure class="highlight java"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">OuterClass.InnerClass</span><br></pre></td></tr></tbody></table></figure>
<h4 id="内部类是否有用、必要和安全（待补充）"><a href="#内部类是否有用、必要和安全（待补充）" class="headerlink" title="内部类是否有用、必要和安全（待补充）"></a>内部类是否有用、必要和安全<font color="#dd0000">（待补充）</font></h4><p>编译器会将内部类转换为常规的类文件，用<code>$</code>符号分隔外部类名与内部类名。比如<code>TalkingClock</code>类内部的<code>TimePrinter</code>类将被转换为类文件<code>TalkingClock$TimePrinter.class</code>。</p>
<p>内部类可以访问外围类的私有数据，外部类则不行。</p>
<h4 id="局部内部类"><a href="#局部内部类" class="headerlink" title="局部内部类"></a>局部内部类</h4><p>前面给的<code>TalkingClock</code>示例代码中，类型<code>TimePrinter</code>的名字只出现了一次，只是在<code>start</code>方法中创建这个类型的对象时使用了一次。当遇到这类情况时，就可以<font color="#dd0000">在一个方法中局部地定义这个类</font>：</p>
<figure class="highlight java"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">start</span><span class="params">()</span> {</span><br><span class="line">    <span class="keyword">class</span> <span class="title class_">TimePrinter</span> <span class="keyword">implements</span> <span class="title class_">ActionPerformed</span> {</span><br><span class="line">        <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">actionPerformed</span><span class="params">(AcitonEvent event)</span> {</span><br><span class="line">            System.out.println(<span class="string">"At the tone,the time is "</span></span><br><span class="line">                              + Instant.ofEpochMilli(event.getWhen()));</span><br><span class="line">            <span class="keyword">if</span>(beep) Toolkit.getDefaultToolkit().beep();</span><br><span class="line">        }</span><br><span class="line">    }</span><br><span class="line">    </span><br><span class="line">    <span class="type">var</span> <span class="variable">listner</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">TimePrinter</span>();</span><br><span class="line">    <span class="type">var</span> <span class="variable">timer</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">Timer</span>(interval,listener);</span><br><span class="line">    timer.start();</span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure>
<font color="#dd0000">声明局部类时不能有访问说明符，局部类的作用域被限定在这个局部类的块中。</font>

<p>局部内部类有个很大的优势，即对外部世界完全隐藏，甚至<code>TalkingClock</code>类中的其他代码也不能访问它。<font color="#dd0000">除了<code>start</code>方法外，没有任何方法知道<code>TimePrinter</code>类的存在。</font></p>
<h4 id="由外部方法访问变量"><a href="#由外部方法访问变量" class="headerlink" title="由外部方法访问变量"></a>由外部方法访问变量</h4><p>局部内部类还有个优点，它们不仅能够访问外部类的字段，还可以访问局部变量！不过，<font color="#dd0000">这里的局部变量必须是<code>事实最终变量</code>，</font>这说明它们一旦赋值就不能够被改变。</p>
<p>看下面的例子，将<code>TalkingClock</code>构造器的参数<code>interval</code>和<code>beep</code>移至<code>star</code>方法：</p>
<figure class="highlight java"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">start</span><span class="params">(<span class="type">int</span> interval, <span class="type">boolean</span> beep)</span> {</span><br><span class="line">    <span class="keyword">class</span> <span class="title class_">TimePrinter</span> <span class="keyword">implements</span> <span class="title class_">ActionPerformed</span> {</span><br><span class="line">        <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">actionPerformed</span><span class="params">(AcitonEvent event)</span> {</span><br><span class="line">            System.out.println(<span class="string">"At the tone,the time is "</span></span><br><span class="line">                              + Instant.ofEpochMilli(event.getWhen()));</span><br><span class="line">            <span class="keyword">if</span>(beep) Toolkit.getDefaultToolkit().beep();</span><br><span class="line">        }</span><br><span class="line">    }</span><br><span class="line">    </span><br><span class="line">    <span class="type">var</span> <span class="variable">listner</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">TimePrinter</span>();</span><br><span class="line">    <span class="type">var</span> <span class="variable">timer</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">Timer</span>(interval,listener);</span><br><span class="line">    timer.start();</span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure>
<p>我们仔细看看这段代码的控制流程：</p>
<ol>
<li>调用<code>start</code>方法。</li>
<li>调用内部类<code>TimePrinter</code>的构造器，以便初始化对象变量<code>listener</code>。</li>
<li>将<code>listener</code>引用传递给<code>Timer</code>构造器，定时器开始计时，<code>start</code>方法开始退出。此时，<code>start</code>方法的<code>beep</code>参数变量不复存在。</li>
<li>1秒之后，<code>actionPerformed</code>方法执行<code>if(beep)</code>···。</li>
</ol>
<p>为了能够让<code>actionPerformed</code>方法中的代码工作，<code>TimePrinter</code>类在<code>beep</code>参数值消失前将<code>beep</code>字段复制为<code>start</code>方法中的局部变量。</p>
<h4 id="匿名内部类"><a href="#匿名内部类" class="headerlink" title="匿名内部类"></a>匿名内部类</h4><p>使用局部内部类时， 还可以再进一步。假如只想创建这个类的一个对象，甚至不需要为类指定一个名字，这样的类被称为<strong>匿名内部类</strong>。它的语法如下：</p>
<figure class="highlight java"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">new</span> <span class="title class_">SuperType</span>(construction parameters) {</span><br><span class="line">    inner <span class="keyword">class</span> <span class="title class_">methods</span> and data; <span class="comment">//内部类属性和方法</span></span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure>
<p>其中，<code>SuperType</code>可以是接口也可以是一个类，内部类需要实现这个接口或者继承这个类。</p>
<p>由于构造器的名字必须与类名相同，而匿名内部类没有类名，所以<font color="#dd0000">匿名内部类不能有构造器</font>。</p>
<p>下面给出一个匿名内部类的例子：</p>
<figure class="highlight java"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></tbody></table></figure>
<h2 id="bookmark-tabs-第八章泛型程序设计"><a href="#bookmark-tabs-第八章泛型程序设计" class="headerlink" title=":bookmark_tabs:第八章泛型程序设计"></a><span class="github-emoji"><span>📑</span><img src="https://github.githubassets.com/images/icons/emoji/unicode/1f4d1.png?v8" aria-hidden="true" onerror="this.parent.classList.add('github-emoji-fallback')"></span>第八章泛型程序设计</h2><h3 id="8-1-定义简单泛型类"><a href="#8-1-定义简单泛型类" class="headerlink" title="8.1 定义简单泛型类"></a>8.1 定义简单泛型类</h3><p><strong>泛型类</strong>就是有一个或多个类型变量的类，类型变量在类名后面用尖括号<code>&lt;&gt;</code>括起来：</p>
<figure class="highlight java"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Pair</span>&lt;T&gt; {</span><br><span class="line">    <span class="keyword">private</span> T first;</span><br><span class="line">    <span class="keyword">private</span> T second;</span><br><span class="line">    <span class="keyword">public</span> <span class="title function_">Pair</span><span class="params">(T first,T second)</span> {</span><br><span class="line">    	<span class="built_in">this</span>.first = first;</span><br><span class="line">        <span class="built_in">this</span>.second = second;</span><br><span class="line">    }</span><br><span class="line">}</span><br></pre></td></tr></tbody></table></figure>
<p>如果有多个类型变量就在尖括号内部用逗号隔开：</p>
<figure class="highlight java"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Pair</span>&lt;T,U&gt; {···}</span><br></pre></td></tr></tbody></table></figure>
<p>类型变量在类的定义中用于指定字段类型与方法返回值类型。</p>
<p>可以用具体的类型替换类型变量来实例化一个泛型类(<strong>菱形语法</strong>)：</p>
<figure class="highlight java"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Pair&lt;String&gt; aPair = Pair&lt;&gt;(<span class="string">"first"</span>,<span class="string">"second"</span>);</span><br></pre></td></tr></tbody></table></figure>
<h3 id="8-2-泛型方法"><a href="#8-2-泛型方法" class="headerlink" title="8.2 泛型方法"></a>8.2 泛型方法</h3><p>定义泛型方法时，将类型变量放在修饰符后面、返回类型的前面。</p>
<p>泛型方法可以在泛型类中定义，也可以在普通类中定义。</p>
<p>调用泛型方法时，将具体类型包围在尖括号内，放在方法名前面：</p>
<figure class="highlight java"><table><tbody><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">String</span> <span class="variable">middle</span> <span class="operator">=</span> ArrayAlg.&lt;String&gt;getMiddle(<span class="string">"ZXF"</span>,<span class="string">"love"</span>,<span class="string">"WJL"</span>);</span><br></pre></td></tr></tbody></table></figure>
<p>多数情况下，泛型方法调用中的类型参数可以省略，编译器可以推断出需要的类型。</p>
<h3 id="8-3-类型变量的限定"><a href="#8-3-类型变量的限定" class="headerlink" title="8.3 类型变量的限定"></a>8.3 类型变量的限定</h3>
      
    </div>

    
    
    

    <footer class="post-footer">
        <div class="post-eof"></div>
      
    </footer>
  </article>
</div>




  <nav class="pagination">
    <a class="extend prev" rel="prev" title="上一页" aria-label="上一页" href="/page/3/"><i class="fa fa-angle-left"></i></a><a class="page-number" href="/">1</a><span class="space">&hellip;</span><a class="page-number" href="/page/3/">3</a><span class="page-number current">4</span>
  </nav>

</div>
  </main>

  <footer class="footer">
    <div class="footer-inner">


<div class="copyright">
  &copy; 
  <span itemprop="copyrightYear">2023</span>
  <span class="with-love">
    <i class="fa fa-heart"></i>
  </span>
  <span class="author" itemprop="copyrightHolder">鸣蜩十七</span>
</div>
  <div class="powered-by">由 <a href="https://hexo.io/" rel="noopener" target="_blank">Hexo</a> & <a href="https://theme-next.js.org/muse/" rel="noopener" target="_blank">NexT.Muse</a> 强力驱动
  </div>

    </div>
  </footer>

  
  <div class="toggle sidebar-toggle" role="button">
    <span class="toggle-line"></span>
    <span class="toggle-line"></span>
    <span class="toggle-line"></span>
  </div>
  <div class="sidebar-dimmer"></div>
  <div class="back-to-top" role="button" aria-label="返回顶部">
    <i class="fa fa-arrow-up fa-lg"></i>
    <span>0%</span>
  </div>

<noscript>
  <div class="noscript-warning">Theme NexT works best with JavaScript enabled</div>
</noscript>


  
  <script src="https://cdnjs.cloudflare.com/ajax/libs/animejs/3.2.1/anime.min.js" integrity="sha256-XL2inqUJaslATFnHdJOi9GfQ60on8Wx1C2H8DYiN1xY=" crossorigin="anonymous"></script>
<script src="/js/comments.js"></script><script src="/js/utils.js"></script><script src="/js/motion.js"></script><script src="/js/schemes/muse.js"></script><script src="/js/next-boot.js"></script>

  




  




  

  <script class="next-config" data-name="enableMath" type="application/json">true</script><script class="next-config" data-name="mathjax" type="application/json">{"enable":true,"tags":"none","js":{"url":"https://cdnjs.cloudflare.com/ajax/libs/mathjax/3.2.2/es5/tex-mml-chtml.js","integrity":"sha256-MASABpB4tYktI2Oitl4t+78w/lyA+D7b/s9GEP0JOGI="}}</script>
<script src="/js/third-party/math/mathjax.js"></script>



</body>
</html>
